home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1998 #3 / Amiga Plus CD - 1998 - No. 3.iso / pd / spiele / frotz / source / amiga.c < prev    next >
C/C++ Source or Header  |  1997-11-06  |  82KB  |  3,334 lines

  1. /*
  2.  * amiga.c
  3.  *
  4.  * IO interface for the Amiga and DICE C
  5.  *
  6.  * Changes to distributed source are indicated by comments containing
  7.  * the keyword AMIGA.
  8.  *
  9.  */
  10.  
  11. #include <proto/amigaguide.h>
  12. #include <proto/asl.h>
  13. #include <proto/diskfont.h>
  14. #include <proto/dos.h>
  15. #include <proto/exec.h>
  16. #include <proto/gadtools.h>
  17. #include <proto/graphics.h>
  18. #include <proto/intuition.h>
  19. #include <proto/keymap.h>
  20. #include <devices/audio.h>
  21. #include <devices/timer.h>
  22. #include <exec/exec.h>
  23. #include <graphics/gfxbase.h>
  24. #include <graphics/gfxmacros.h>
  25. #include <graphics/videocontrol.h>
  26. #include <intuition/imageclass.h>
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <time.h>
  32. #include "frotz.h"
  33. #include "amiga.h"
  34.  
  35. #define INFORMATION "\
  36. \n\
  37. FROTZ V2.32 - interpreter for all Infocom games. Complies with standard\n\
  38. 1.0 of Graham Nelson's specification. Written by Stefan Jokisch in 1995-7\n\
  39. Amiga version by David Kinder\n\
  40. \n\
  41. Syntax: frotz [options] story-file\n\
  42. \n\
  43.   -a   watch attribute setting  \t -p   alter piracy opcode\n\
  44.   -A   watch attribute testing  \t -r # right margin\n\
  45.   -c # context lines            \t -s # random number seed value\n\
  46.   -i   ignore runtime errors    \t -S # transscript width\n\
  47.   -l # left margin              \t -t   set Tandy bit\n\
  48.   -o   watch object movement    \t -u # slots for multiple undo\n\
  49.   -O   watch object locating    \t -x   expand abbreviations g/x/z"
  50.  
  51. static unsigned char graphic_font[] = {
  52.   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  53.   0x00, 0x30, 0x70, 0xFF, 0x70, 0x30, 0x00, 0x00,
  54.   0x00, 0x0C, 0x0E, 0xFF, 0x0E, 0x0C, 0x00, 0x00,
  55.   0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
  56.   0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
  57.   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  58.   0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
  59.   0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
  60.   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  61.   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  62.   0x08, 0x08, 0x08, 0xFF, 0x00, 0x00, 0x00, 0x00,
  63.   0x00, 0x00, 0x00, 0x00, 0xFF, 0x08, 0x08, 0x08,
  64.   0x08, 0x08, 0x08, 0x08, 0x0F, 0x08, 0x08, 0x08,
  65.   0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x10, 0x10,
  66.   0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00,
  67.   0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x10,
  68.   0x00, 0x00, 0x00, 0xF8, 0x08, 0x08, 0x08, 0x08,
  69.   0x08, 0x08, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00,
  70.   0x10, 0x10, 0x10, 0x10, 0x1F, 0x20, 0x40, 0x80,
  71.   0x80, 0x40, 0x20, 0x1F, 0x10, 0x10, 0x10, 0x10,
  72.   0x01, 0x02, 0x04, 0xF8, 0x08, 0x08, 0x08, 0x08,
  73.   0x08, 0x08, 0x08, 0x08, 0xF8, 0x04, 0x02, 0x01,
  74.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  75.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  76.   0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  77.   0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
  78.   0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
  79.   0x08, 0x08, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  80.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x08, 0x08,
  81.   0xF8, 0xF8, 0xF8, 0xF8, 0xFF, 0xF8, 0xF8, 0xF8,
  82.   0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0x1F, 0x1F, 0x1F,
  83.   0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00,
  84.   0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
  85.   0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
  86.   0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, 0x00,
  87.   0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x40, 0x80,
  88.   0x80, 0x40, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
  89.   0x01, 0x02, 0x04, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
  90.   0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x04, 0x02, 0x01,
  91.   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  92.   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  93.   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
  94.   0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  95.   0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  96.   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
  97.   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  98.   0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  99.   0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
  100.   0x00, 0xFF, 0x80, 0x80, 0x80, 0x80, 0xFF, 0x00,
  101.   0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0x00,
  102.   0x00, 0xFF, 0xE0, 0xE0, 0xE0, 0xE0, 0xFF, 0x00,
  103.   0x00, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0x00,
  104.   0x00, 0xFF, 0xF8, 0xF8, 0xF8, 0xF8, 0xFF, 0x00,
  105.   0x00, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0x00,
  106.   0x00, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x00,
  107.   0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
  108.   0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
  109.   0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
  110.   0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
  111.   0x08, 0x08, 0x08, 0x08, 0xFF, 0x08, 0x08, 0x08,
  112.   0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
  113.   0x00, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18,
  114.   0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
  115.   0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF,
  116.   0x00, 0x3C, 0x66, 0x06, 0x18, 0x00, 0x18, 0x00,
  117.   0x63, 0x76, 0x5C, 0x60, 0x78, 0x66, 0x60, 0x00,
  118.   0x78, 0x6E, 0x63, 0x7C, 0x63, 0x6E, 0x78, 0x00,
  119.   0x00, 0x1E, 0x1B, 0x18, 0x18, 0xD8, 0x78, 0x00,
  120.   0x63, 0x63, 0x77, 0x49, 0x77, 0x63, 0x63, 0x00,
  121.   0x63, 0x77, 0x6B, 0x6B, 0x63, 0x63, 0x63, 0x00,
  122.   0x49, 0x52, 0x64, 0x68, 0x70, 0x60, 0x60, 0x00,
  123.   0x00, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00,
  124.   0x63, 0x53, 0x4F, 0x63, 0x79, 0x65, 0x63, 0x00,
  125.   0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00,
  126.   0x18, 0x18, 0x7E, 0x99, 0x7E, 0x18, 0x18, 0x00,
  127.   0x60, 0x60, 0x78, 0x6C, 0x67, 0x63, 0x63, 0x00,
  128.   0x38, 0x3C, 0x36, 0x30, 0x30, 0x30, 0x30, 0x00,
  129.   0x77, 0x6B, 0x77, 0x63, 0x63, 0x63, 0x63, 0x00,
  130.   0x18, 0xD8, 0x78, 0x3C, 0x1E, 0x1B, 0x18, 0x00,
  131.   0x71, 0x6A, 0x64, 0x71, 0x6A, 0x64, 0x60, 0x00,
  132.   0x60, 0x60, 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x00,
  133.   0x18, 0x18, 0x18, 0x18, 0x3C, 0x5A, 0xDB, 0x00,
  134.   0x7C, 0x63, 0x63, 0x7C, 0x66, 0x63, 0x63, 0x00,
  135.   0x60, 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x03, 0x00,
  136.   0x18, 0x3C, 0x5A, 0x99, 0x18, 0x18, 0x18, 0x00,
  137.   0x70, 0x78, 0x6C, 0x66, 0x63, 0x63, 0x63, 0x00,
  138.   0x7E, 0x03, 0x7E, 0x03, 0x03, 0x03, 0x7C, 0x00,
  139.   0x70, 0x6C, 0x63, 0x6C, 0x78, 0x60, 0x60, 0x00,
  140.   0xDB, 0x5A, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00,
  141.   0x78, 0x64, 0x52, 0x49, 0x4F, 0x49, 0x49, 0x00,
  142.   0x60, 0x63, 0x66, 0x6C, 0x78, 0x60, 0x60, 0x00,
  143.   0xE7, 0xC3, 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF,
  144.   0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0x81, 0xC3, 0xE7,
  145.   0xE7, 0xC3, 0x81, 0xE7, 0xE7, 0x81, 0xC3, 0xE7,
  146.   0xFF, 0xC3, 0x99, 0xF9, 0xE7, 0xFF, 0xE7, 0xFF
  147. };
  148.  
  149. USHORT ZColours[11] =
  150. {
  151.   0x0000,0x0E00,0x00C0,0x0EE0,0x005A,0x0F0F,0x00EE,0x0FFF,
  152.   0x0AAA,0x0777,0x0444
  153. };
  154. LONG ZMachinePens[16] =
  155. { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
  156. int UsePenTable;
  157.  
  158. USHORT CustomColours[16];
  159. USHORT SystemColours[16];
  160.  
  161. static int current_style = 0;
  162. static int current_font = 0;
  163. static int saved_style = 0;
  164. static int saved_font = 0;
  165. static int user_tandy_bit = -1;
  166. static int user_random_seed = -1;
  167. static int cursor_state = 0;
  168.  
  169. int last_text_out = 0;
  170. int current_game = 0;
  171. int justify_pending = 0;
  172.  
  173. int getopt (int, char *[], const char *);
  174.  
  175. extern const char *optarg;
  176. extern int optind;
  177.  
  178. #define HISTORY_LINES 20
  179. unsigned char *History[HISTORY_LINES];
  180. int HistoryPosition = HISTORY_LINES;
  181.  
  182. #define TEXTBUFFER_SIZE 256
  183. #define QUALIFIER_SHIFT (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)
  184. #define QUALIFIER_ALT (IEQUALIFIER_LALT|IEQUALIFIER_RALT)
  185.  
  186. struct NewMenu NewMenus[] =
  187.  {{ NM_TITLE,"Project",0,0,0,0 },
  188.   { NM_ITEM,"Prefs...","F",0,0,0 },
  189.   { NM_ITEM,"Help...","H",0,0,0 },
  190.   { NM_ITEM,"About...","?",0,0,0 },
  191.   { NM_ITEM,NM_BARLABEL,0,0,0,0 },
  192.   { NM_ITEM,"Quit","Q",0,0,0 },
  193.   { NM_TITLE,"Game",0,0,0,0 },
  194.   { NM_ITEM,"Restore...","O",0,0,"restore" },
  195.   { NM_ITEM,"Save...","S",0,0,"save" },
  196.   { NM_ITEM,"Restart","R",0,0,"restart" },
  197.   { NM_ITEM,NM_BARLABEL,0,0,0,0 },
  198.   { NM_ITEM,"Script","P",0,0,"script" },
  199.   { NM_ITEM,"Unscript","U",0,0,"unscript" },
  200.   { NM_ITEM,NM_BARLABEL,0,0,0,0 },
  201.   { NM_ITEM,"Superbrief","<",0,0,"superbrief" },
  202.   { NM_ITEM,"Brief",".",0,0,"brief" },
  203.   { NM_ITEM,"Verbose",">",0,0,"verbose" },
  204.   { NM_ITEM,NM_BARLABEL,0,0,0,0 },
  205.   { NM_ITEM,"Tandy Flag",0,CHECKIT|MENUTOGGLE,0,0 },
  206.   { NM_TITLE,"Commands",0,0,0,0 },
  207.   { NM_ITEM,"Look","L",0,0,"look" },
  208.   { NM_ITEM,"Inventory","I",0,0,"inventory" },
  209.   { NM_ITEM,NM_BARLABEL,0,0,0,0 },
  210.   { NM_ITEM,"Diagnose","D",0,0,"diagnose" },
  211.   { NM_ITEM,"Score","C",0,0,"score" },
  212.   { NM_ITEM,"Time","T",0,0,"time" },
  213.   { NM_ITEM,NM_BARLABEL,0,0,0,0 },
  214.   { NM_ITEM,"Wait","Z",0,0,"wait" },
  215.   { NM_ITEM,"Again","G",0,0,"again" },
  216.   { NM_ITEM,NM_BARLABEL,0,0,0,0 },
  217.   { NM_ITEM,"Yes","Y",0,0,"yes" },
  218.   { NM_ITEM,"No","N",0,0,"no" },
  219.   { NM_END,0,0,0,0,0 }};
  220.  
  221. WORD ScreenPens[] = { -1 };
  222. char Version[] = "$VER:Frotz 2.32 (6.11.97)";
  223. char TitleBar[] = "Frotz 2.32 Amiga Release 10";
  224. unsigned char TextBuffer[TEXTBUFFER_SIZE];
  225. unsigned char LengthBuffer[TEXTBUFFER_SIZE];
  226. unsigned long TextBufferPtr;
  227.  
  228. extern struct Library *IntuitionBase;
  229. extern struct GfxBase *GfxBase;
  230. struct Library *KeymapBase;
  231. struct Library *AmigaGuideBase;
  232. struct Screen *Screen;
  233. struct Screen *DefaultPubScreen;
  234. struct Window *Window;
  235. struct Window *OldWindowPtr;
  236. struct RastPort *RastPort;
  237. struct Menu *Menus;
  238. struct FileRequester *FileRequester;
  239. struct Process *ThisProcess;
  240. struct WBStartup *WBMessage;
  241. struct DiskObject *SaveIcon;
  242. struct List *SearchDirs;
  243. struct List *ExcludeDirs;
  244. struct List *GamesList;
  245. struct Preferences FrotzPrefs;
  246. struct MorePreferences MoreFrotzPrefs;
  247. APTR Visual;
  248.  
  249. ULONG ForeColour = 1;
  250. ULONG BackColour = 0;
  251. ULONG RevForeColour = 2;
  252. ULONG RevBackColour = 3;
  253. ULONG InputColour = 2;
  254. int UsingColour = 0;
  255.  
  256. struct TextFont *ScreenFont;
  257. struct TextFont *TextFont, *OpenedTextFont;
  258. struct TextFont *FixedFont, *OpenedFixedFont;
  259. int EmphasisStyle;
  260.  
  261. struct timerequest *TimerRequest;
  262. struct MsgPort *TimerMsgPort;
  263. int TimerOpenCode = -1;
  264. int TimerActive;
  265.  
  266. int ScreenWidth, ScreenHeight;
  267. int ScaleX, ScaleY;
  268. int TextWidth, TextHeight;
  269. int PreviousRows;
  270.  
  271. struct SampleHeader
  272. {
  273.   unsigned short Length;
  274.   unsigned char     Times;
  275.   unsigned char  BaseNote;
  276.   unsigned short Frequency;
  277.   unsigned char     Blank[2];
  278.   unsigned short SampleLength;
  279. };
  280.  
  281. struct MacintoshMid
  282. {
  283.   unsigned short Length;
  284.   unsigned char     Commands[11];
  285.   unsigned char  SoundFileName[19];
  286. };
  287.  
  288. #define MAC_OFFSET 68
  289.  
  290. struct IOAudio *SoundRequest, *SoundLeftRequest, *SoundRightRequest;
  291. struct MsgPort *SoundMsgPort;
  292. struct SampleHeader *SampleHeader;
  293. int SoundOpenCode = -1;
  294. int CurrentSample;
  295. int SampleUnsigned;
  296. int SamplePlaying;
  297. char *SampleMemory;
  298. char SoundDirectory[MAX_FILE_NAME+1];
  299.  
  300. struct GraphicsHeader
  301. {
  302.   unsigned char  Part;
  303.   unsigned char  Flags;
  304.   unsigned short Unknown1;
  305.   unsigned short Images;
  306.   unsigned short Link;
  307.   unsigned char  InfoSize;
  308.   unsigned char  Unused;
  309.   unsigned short Checksum;
  310.   unsigned short Unknown2;
  311.   unsigned short Version;
  312. };
  313.  
  314. #define PIC_NUMBER 0
  315. #define PIC_WIDTH  2
  316. #define PIC_HEIGHT 4
  317. #define PIC_FLAGS  6
  318. #define PIC_DATA   8
  319. #define PIC_COLOUR 11
  320.  
  321. #define GFX_IBM_MCGA 1
  322. #define GFX_IBM_CGA  2
  323. #define GFX_AMIGA    3
  324.  
  325. char *GfxMemory;
  326. struct GraphicsHeader *GfxHeader;
  327. int GfxType;
  328. unsigned short TableSeq[3840];
  329. unsigned char TableVal[3840];
  330.  
  331. int InputMax1,InputMax2;
  332.  
  333. /*
  334.  * os_beep
  335.  *
  336.  * Play a beep sound. Ideally, the sound should be high- (number == 1)
  337.  * or low-pitched (number == 2).
  338.  *
  339.  */
  340.  
  341. void os_beep (int number)
  342. {
  343.   DisplayBeep(Window->WScreen);
  344. }
  345.  
  346. /*
  347.  * os_display_char
  348.  *
  349.  * Display a character of the current font using the current colours and
  350.  * text style. The cursor moves to the next position. Printable codes are
  351.  * all ASCII values from 32 to 126, ISO Latin-1 characters from 160 to
  352.  * 255, ZC_GAP (gap between two sentences) and ZC_INDENT (paragraph
  353.  * indentation). The screen should not be scrolled after printing to the
  354.  * bottom right corner.
  355.  *
  356.  */
  357.  
  358. void os_display_char (zchar c)
  359. {
  360. unsigned long bcol;
  361.  
  362.   if (h_version != V6) last_text_out = 1;
  363.  
  364.   if (current_font == GRAPHICS_FONT)
  365.   {
  366.     if (RastPort->DrawMode&INVERSVID)
  367.     {
  368.       bcol = RastPort->BgPen;
  369.       SetBPen(RastPort,RastPort->FgPen);
  370.     }
  371.     SafeRectFill(RastPort,
  372.       RastPort->cp_x,
  373.       RastPort->cp_y,
  374.       RastPort->cp_x+TextWidth-1,
  375.       RastPort->cp_y+TextHeight-1,
  376.       RastPort->BgPen);
  377.     if (RastPort->DrawMode&INVERSVID) SetBPen(RastPort,bcol);
  378.  
  379.     if ((TextWidth == 8) && (TextHeight == 8))
  380.     {
  381.     int i;
  382.     __chip static unsigned short graphics_char[8];
  383.  
  384.       for (i = 0; i < 8; i++)
  385.     graphics_char[i] = graphic_font[((c-32)<<3)+i]<<8;
  386.       BltPattern(RastPort,graphics_char,RastPort->cp_x,RastPort->cp_y,
  387.     RastPort->cp_x+7,RastPort->cp_y+7,2);
  388.     }
  389.     else
  390.     {
  391.     int i,j;
  392.     unsigned char unscaled;
  393.  
  394.       for (i = 0; i < TextHeight; i++)
  395.       {
  396.     unscaled = graphic_font[((c-32)<<3)+((i*7)/(TextHeight-1))];
  397.     for (j = 0; j < TextWidth; j++)
  398.     {
  399.       if (unscaled & (128>>((j*7)/(TextWidth-1))))
  400.         WritePixel(RastPort,RastPort->cp_x+j,RastPort->cp_y+i);
  401.     }
  402.       }
  403.     }
  404.     Move(RastPort,RastPort->cp_x+TextWidth,RastPort->cp_y);
  405.   }
  406.   else
  407.   {
  408.     if (c == ZC_INDENT)
  409.     {
  410.       os_display_char(' ');
  411.       os_display_char(' ');
  412.       os_display_char(' ');
  413.       return;
  414.     }
  415.     if (c == ZC_GAP)
  416.     {
  417.       os_display_char(' ');
  418.       os_display_char(' ');
  419.       return;
  420.     }
  421.  
  422.     if ((c >= ZC_ASCII_MIN && c <= ZC_ASCII_MAX) || (c >= ZC_LATIN1_MIN && c <= ZC_LATIN1_MAX))
  423.     {
  424.       if (TextBufferPtr == TEXTBUFFER_SIZE) FlushText();
  425.       *(TextBuffer+(TextBufferPtr++)) = c;
  426.     }
  427.   }
  428. }
  429.  
  430. /*
  431.  * os_display_string
  432.  *
  433.  * Pass a string of characters to os_display_char.
  434.  *
  435.  */
  436.  
  437. void os_display_string (const zchar *s)
  438. {
  439. zchar c;
  440.  
  441.   while ((c = *s++) != 0)
  442.   {
  443.     if (c == ZC_NEW_FONT || c == ZC_NEW_STYLE)
  444.     {
  445.       int arg = (zchar)*s++;
  446.  
  447.       if (c == ZC_NEW_FONT) os_set_font(arg);
  448.       if (c == ZC_NEW_STYLE) os_set_text_style(arg);
  449.     }
  450.     else os_display_char(c);
  451.   }
  452. }
  453.  
  454. /*
  455.  * os_erase_area
  456.  *
  457.  * Fill a rectangular area of the screen with the current background
  458.  * colour. Top left coordinates are (1,1). The cursor does not move.
  459.  *
  460.  */
  461.  
  462. void os_erase_area (int top, int left, int bottom, int right)
  463. {
  464.   FlushText();
  465.   SafeRectFill(RastPort,
  466.     Window->BorderLeft+left-1,
  467.     Window->BorderTop+top-1,
  468.     Window->BorderLeft+right-1,
  469.     Window->BorderTop+bottom-1,
  470.     UsingColour != 0 ? RastPort->BgPen : BackColour);
  471. }
  472.  
  473. /*
  474.  * os_fatal
  475.  *
  476.  * Display error message and stop interpreter.
  477.  *
  478.  */
  479.  
  480. void os_fatal (const char *s)
  481. {
  482.   os_stop_sample();
  483.  
  484.   if (WBMessage)
  485.   {
  486.     Requester(0,"Fatal error: %s","Cancel",s);
  487.   }
  488.   else
  489.   {
  490.     fputs("\nFatal error: ",stderr);
  491.     fputs(s,stderr);
  492.     fputs("\n",stderr);
  493.   }
  494.  
  495.   Quit(1);
  496. }
  497.  
  498. /*
  499.  * os_finish_with_sample
  500.  *
  501.  * Remove the current sample from memory (if any).
  502.  *
  503.  */
  504.  
  505. void os_finish_with_sample (void)
  506. {
  507.   os_stop_sample();
  508.  
  509.   if (CurrentSample != 0)
  510.   {
  511.     FreeVec(SampleMemory);
  512.     CurrentSample = 0;
  513.   }
  514. }
  515.  
  516. /*
  517.  * os_font_data
  518.  *
  519.  * Return true if the given font is available. The font can be
  520.  *
  521.  *    TEXT_FONT
  522.  *    PICTURE_FONT
  523.  *    GRAPHICS_FONT
  524.  *    FIXED_WIDTH_FONT
  525.  *
  526.  * The font size should be stored in "height" and "width". If
  527.  * the given font is unavailable then these values must _not_
  528.  * be changed.
  529.  *
  530.  */
  531.  
  532. int os_font_data (int font, int *height, int *width)
  533. {
  534.   *height = h_font_height;
  535.   *width = h_font_width;
  536.  
  537.   if (font == TEXT_FONT) return 1;
  538.   if (font == GRAPHICS_FONT) return 1;
  539.   if (font == FIXED_WIDTH_FONT)    return 1;
  540.   return 0;
  541. }
  542.  
  543. /*
  544.  * os_read_file_name
  545.  *
  546.  * Return the name of a file. Flag can be one of:
  547.  *
  548.  *    FILE_SAVE     - Save game file
  549.  *    FILE_RESTORE  - Restore game file
  550.  *    FILE_SCRIPT   - Transscript file
  551.  *    FILE_RECORD   - Command file for recording
  552.  *    FILE_PLAYBACK - Command file for playback
  553.  *    FILE_SAVE_AUX - Save auxilary ("preferred settings") file
  554.  *    FILE_LOAD_AUX - Load auxilary ("preferred settings") file
  555.  *
  556.  * The length of the file name is limited by MAX_FILE_NAME. Ideally
  557.  * an interpreter should open a file requester to ask for the file
  558.  * name. If it is unable to do that then this function should call
  559.  * print_string and read_string to ask for a file name.
  560.  *
  561.  */
  562.  
  563. int os_read_file_name (char *file_name, const char *default_name, int flag)
  564. {
  565. FILE *fp;
  566. char dir_buffer[MAX_FILE_NAME+1];
  567. char file_buffer[MAX_FILE_NAME+1];
  568. int saved_replay = istream_replay;
  569. int saved_record = ostream_record;
  570. int result = 0;
  571.  
  572.   istream_replay = 0;
  573.   ostream_record = 0;
  574.  
  575.   if (flag != FILE_SCRIPT || MoreFrotzPrefs.Flags & PREFS_ALLFREQ)
  576.   {
  577.     if (FileRequester)
  578.     {
  579.     char *title;
  580.     int save = 0;
  581.  
  582.       switch (flag)
  583.       {
  584.     case FILE_SAVE:
  585.       title = "Save Game";
  586.       save = 1;
  587.       break;
  588.     case FILE_RESTORE:
  589.       title = "Restore Game";
  590.       break;
  591.     case FILE_RECORD:
  592.       title = "Save Record";
  593.       save = 1;
  594.       break;
  595.     case FILE_PLAYBACK:
  596.       title = "Play Record";
  597.       break;
  598.     case FILE_SAVE_AUX:
  599.       title = "Save Auxiliary";
  600.       save = 1;
  601.       break;
  602.     case FILE_LOAD_AUX:
  603.       title = "Load Auxiliary";
  604.       break;
  605.     case FILE_SCRIPT:
  606.       title = "Script File";
  607.       save = 1;
  608.       break;
  609.       }
  610.       strcpy(dir_buffer,default_name);
  611.       *(FilePart(dir_buffer)) = 0;
  612.       strcpy(file_buffer,FilePart(default_name));
  613.  
  614.     int asl_return;
  615.  
  616.       SetColourScheme(0);
  617.       asl_return = AslRequestTags(FileRequester,
  618.     ASLFR_TitleText,title,
  619.     ASLFR_InitialDrawer,dir_buffer,
  620.     ASLFR_InitialFile,file_buffer,
  621.     ASLFR_DoSaveMode,save,TAG_DONE);
  622.       SetColourScheme(1);
  623.       if (asl_return)
  624.       {
  625.     strcpy(file_name,FileRequester->fr_Drawer);
  626.     AddPart(file_name,FileRequester->fr_File,MAX_FILE_NAME);
  627.  
  628.     if ((flag == FILE_SAVE) && (SaveIcon))
  629.       PutDiskObject(file_name,SaveIcon);
  630.     result = 1;
  631.       }
  632.       goto finished;
  633.     }
  634.   }
  635.  
  636.   print_string("Enter a file name.\n");
  637.   print_string("Default is \"");
  638.   print_string(default_name);
  639.   print_string("\": ");
  640.  
  641.   read_string(MAX_FILE_NAME-4,file_name);
  642.   if (file_name[0] == 0) strcpy(file_name,default_name);
  643.  
  644.   result = 1;
  645.   if (flag == FILE_SAVE || flag == FILE_SAVE_AUX || flag == FILE_RECORD)
  646.   {
  647.     if ((fp = fopen(file_name,"rb")) == NULL) goto finished;
  648.     fclose(fp);
  649.     result = read_yes_or_no("Overwrite existing file");
  650.   }
  651.  
  652. finished:
  653.  
  654.   istream_replay = saved_replay;
  655.   ostream_record = saved_record;
  656.   return result;
  657. }
  658.  
  659. /*
  660.  * os_init_screen
  661.  *
  662.  * Initialise the IO interface. Prepare screen and other devices
  663.  * (mouse, sound card). Set various OS depending story file header
  664.  * entries:
  665.  *
  666.  *     h_config (aka flags 1)
  667.  *     h_flags (aka flags 2)
  668.  *     h_screen_cols (aka screen width in characters)
  669.  *     h_screen_rows (aka screen height in lines)
  670.  *     h_screen_width
  671.  *     h_screen_height
  672.  *     h_font_height (defaults to 1)
  673.  *     h_font_width (defaults to 1)
  674.  *     h_default_foreground
  675.  *     h_default_background
  676.  *     h_interpreter_number
  677.  *     h_interpreter_version
  678.  *     h_user_name (optional; not used by any game)
  679.  *
  680.  * Finally, set reserve_mem to the amount of memory (in bytes) that
  681.  * should not be used for multiple undo and reserved for later use.
  682.  *
  683.  */
  684.  
  685. void os_init_screen (void)
  686. {
  687. static struct TextAttr new_font;
  688. unsigned long screen;
  689. int show_title = 1;
  690.  
  691.   ReadGamesFile();
  692.   current_game = ScanForGame(h_release,h_serial,h_checksum);
  693.   UsingColour = 0;
  694.  
  695.   if ((KeymapBase = OpenLibrary("keymap.library",37)) == 0) Quit(1);
  696.  
  697.   new_font.ta_Name = FrotzPrefs.TextFontName;
  698.   new_font.ta_YSize = FrotzPrefs.TextFontSize;
  699.   OpenedTextFont = OpenCorrectFont(&new_font);
  700.   TextFont = OpenedTextFont;
  701.   new_font.ta_Name = FrotzPrefs.FixedFontName;
  702.   new_font.ta_YSize = FrotzPrefs.FixedFontSize;
  703.   OpenedFixedFont = OpenCorrectFont(&new_font);
  704.   FixedFont = OpenedFixedFont;
  705.  
  706.   if (h_version >= V5)
  707.   {
  708.     switch (FrotzPrefs.Colour)
  709.     {
  710.       case COLOUR_BZ_ONLY:
  711.     if (story_id == BEYOND_ZORK) UsingColour = 2;
  712.     break;
  713.       case COLOUR_BZ_AND_V6:
  714.     if (story_id == BEYOND_ZORK) UsingColour = 2;
  715.     if (h_version == V6) UsingColour = 3;
  716.     break;
  717.       case COLOUR_ALL_GAMES:
  718.     UsingColour = 1;
  719.     if (story_id == BEYOND_ZORK) UsingColour = 2;
  720.     if (h_version == V6) UsingColour = 3;
  721.     break;
  722.     }
  723.   }
  724.  
  725.   if ((DefaultPubScreen = LockPubScreen(0)) == 0) Quit(1);
  726.   screen = FrotzPrefs.CustomScreen;
  727.   if (screen)
  728.   {
  729.   static struct TextAttr screen_font;
  730.   static char screen_font_name[MAXFONTNAME];
  731.  
  732.     strcpy(screen_font_name,MoreFrotzPrefs.ScreenFontName);
  733.     screen_font.ta_Name = screen_font_name;
  734.     screen_font.ta_YSize = MoreFrotzPrefs.ScreenFontSize;
  735.     ScreenFont = OpenDiskFont(&screen_font);
  736.  
  737.     if (h_version == V6 && MoreFrotzPrefs.Flags & PREFS_NO_V6_TITLE)
  738.       show_title = 0;
  739.  
  740.     Screen = OpenScreenTags(0,
  741.       SA_Pens,ScreenPens,
  742.       SA_DisplayID,FrotzPrefs.ScreenMode,
  743.       SA_Overscan,OSCAN_TEXT,
  744.       SA_Depth,UsingColour ? 4 : 2,
  745.       SA_Interleaved,1,
  746.       SA_Type,CUSTOMSCREEN|AUTOSCROLL,
  747.       SA_Font,&screen_font,
  748.       SA_Title,TitleBar,
  749.       SA_ShowTitle,show_title,
  750.       SA_Behind,1,TAG_DONE);
  751.     if (Screen == 0) Quit(1);
  752.     GetScreenRatio(Screen);
  753.  
  754.     if (MoreFrotzPrefs.Colours[0] != 0xFFFF)
  755.     {
  756.       CustomColours[0] = MoreFrotzPrefs.Colours[0];
  757.       CustomColours[1] = MoreFrotzPrefs.Colours[1];
  758.       CustomColours[2] = MoreFrotzPrefs.Colours[2];
  759.       CustomColours[3] = MoreFrotzPrefs.Colours[3];
  760.     }
  761.     else
  762.     {
  763.       CustomColours[0] = GetRGB4(DefaultPubScreen->ViewPort.ColorMap,0);
  764.       CustomColours[1] = GetRGB4(DefaultPubScreen->ViewPort.ColorMap,1);
  765.       CustomColours[2] = GetRGB4(DefaultPubScreen->ViewPort.ColorMap,2);
  766.       CustomColours[3] = GetRGB4(DefaultPubScreen->ViewPort.ColorMap,3);
  767.     }
  768.  
  769.     if (UsingColour)
  770.     {
  771.       CopyMem(ZColours,CustomColours+4,8*sizeof(USHORT));
  772.       CopyMem(CustomColours,CustomColours+12,4*sizeof(USHORT));
  773.       CopyMem(CustomColours,SystemColours,16*sizeof(USHORT));
  774.       LoadRGB4(&Screen->ViewPort,CustomColours,16);
  775.     }
  776.     else
  777.     {
  778.       if (MoreFrotzPrefs.Colours[0] != 0xFFFF)
  779.     LoadRGB4(&Screen->ViewPort,CustomColours,4);
  780.     }
  781.  
  782.   }
  783.   else
  784.   {
  785.   int i;
  786.  
  787.     GetScreenRatio(DefaultPubScreen);
  788.     if (IntuitionBase->lib_Version >= 39)
  789.     {
  790.       if (UsingColour)
  791.       {
  792.     for (i = 0; i < 16; i++)
  793.     {
  794.       ZMachinePens[i] = ObtainPen(
  795.         DefaultPubScreen->ViewPort.ColorMap,-1,0,0,0,PEN_EXCLUSIVE);
  796.     }
  797.     UsePenTable = 1;
  798.     for (i = 0; i < 16; i++)
  799.     {
  800.       if (ZMachinePens[i] == -1) FreePenTable();
  801.     }
  802.     if (UsePenTable == 0) UsingColour = 0;
  803.       }
  804.     }
  805.     else UsingColour = 0;
  806.   }
  807.  
  808. short left,top,width,height;
  809.  
  810.   if (MoreFrotzPrefs.Window[2] > 0)
  811.   {
  812.     left = MoreFrotzPrefs.Window[0];
  813.     top = MoreFrotzPrefs.Window[1];
  814.     width = MoreFrotzPrefs.Window[2];
  815.     height = MoreFrotzPrefs.Window[3];
  816.   }
  817.   else
  818.   {
  819.     left = 0;
  820.     top = DefaultPubScreen->BarHeight+1;
  821.     width = ScreenWidth;
  822.     height = ScreenHeight-DefaultPubScreen->BarHeight-1;
  823.   }
  824.  
  825. int window_left,window_top,window_width,window_height;
  826.  
  827.   window_left = screen ? 0 : left;
  828.   window_width = screen ? Screen->Width : width;
  829.   if (screen)
  830.   {
  831.     window_top = show_title ? 2 : 0;
  832.     window_height = show_title ? Screen->Height-2 : Screen->Height;
  833.   }
  834.   else
  835.   {
  836.     window_top = top;
  837.     window_height = height;
  838.   }
  839.  
  840.   if (h_version == V6 && MoreFrotzPrefs.V6Style == V6_640200)
  841.   {
  842.   int min_width = 640;
  843.   int min_height = 200;
  844.  
  845.     if (screen)
  846.     {
  847.       if (show_title) min_height += Screen->Font->ta_YSize;
  848.     }
  849.     else
  850.     {
  851.       min_width += DefaultPubScreen->WBorLeft+DefaultPubScreen->WBorRight;
  852.       min_height += DefaultPubScreen->WBorTop+1+
  853.     DefaultPubScreen->Font->ta_YSize+SizeGadgetHeight(DefaultPubScreen);
  854.     }
  855.     window_width =
  856.       MIN(min_width,screen ? Screen->Width : DefaultPubScreen->Width);
  857.     window_height =
  858.       MIN(min_height,screen ? Screen->Height : DefaultPubScreen->Height);
  859.   }    
  860.  
  861.   if (MoreFrotzPrefs.Flags & PREFS_CENTRE_WINDOW)
  862.   {
  863.     if (screen)
  864.     {
  865.       window_left = (Screen->Width-window_width)/2;
  866.     }
  867.     else
  868.     {
  869.       window_left = (DefaultPubScreen->Width-window_width)/2;
  870.       window_top = (DefaultPubScreen->Height-window_height)/2;
  871.     }
  872.   }
  873.     
  874.   if ((Window = OpenWindowTags(0,
  875.     WA_Left,window_left,
  876.     WA_Top,window_top,
  877.     WA_Width,window_width,
  878.     WA_Height,window_height,
  879.     WA_SmartRefresh,1,
  880.     WA_NewLookMenus,1,
  881.     WA_AutoAdjust,1-screen,
  882.     WA_Borderless,screen,
  883.     WA_Backdrop,screen,
  884.     WA_Activate,1-screen,
  885.     WA_CloseGadget,1-screen,
  886.     WA_DragBar,1-screen,
  887.     WA_DepthGadget,1-screen,
  888.     WA_SizeGadget,1-screen,
  889.     WA_SizeBBottom,1-screen,
  890.     show_title ? WA_Title : TAG_IGNORE,TitleBar,
  891.     WA_ScreenTitle,TitleBar,
  892.     WA_IDCMP,IDCMP_RAWKEY|IDCMP_MENUPICK|IDCMP_MOUSEBUTTONS|IDCMP_CLOSEWINDOW|IDCMP_CHANGEWINDOW,
  893.     screen ? WA_CustomScreen : WA_PubScreen, screen ? Screen : DefaultPubScreen,
  894.     TAG_DONE)) == 0) Quit(1);
  895.  
  896.   SetZColours();
  897.   ThisProcess = (struct Process *)FindTask(0);
  898.   OldWindowPtr = ThisProcess->pr_WindowPtr;
  899.   ThisProcess->pr_WindowPtr = Window;
  900.   ScreenToFront(Window->WScreen);
  901.   ActivateWindow(Window);
  902.  
  903.   if ((Visual = GetVisualInfo(Window->WScreen,TAG_DONE)) == 0) Quit(1);
  904.   if ((Menus = CreateMenus(NewMenus,GTMN_NewLookMenus,TRUE,TAG_DONE)) == 0) Quit(1);
  905.   LayoutMenus(Menus,Visual,GTMN_NewLookMenus,TRUE,TAG_DONE);
  906.   SetMenuStrip(Window,Menus);
  907.  
  908.   if (h_version == V3)
  909.   {
  910.     if (user_tandy_bit != -1)
  911.       ItemAddress(Menus,FULLMENUNUM(1,11,0))->Flags |= CHECKED;
  912.   }
  913.   else OffMenu(Window,FULLMENUNUM(1,11,0));
  914.  
  915.   RastPort = Window->RPort;
  916.   SetDrMd(RastPort,JAM2);
  917.   SetFont(RastPort,FixedFont);
  918.   TextWidth = RastPort->TxWidth;
  919.   TextHeight = RastPort->TxHeight;
  920.  
  921.   if ((TimerMsgPort = CreateMsgPort()) == 0) Quit(1);
  922.   if ((TimerRequest = CreateIORequest(TimerMsgPort,sizeof(struct timerequest))) == 0) Quit(1);
  923.   if ((TimerOpenCode = OpenDevice("timer.device",UNIT_VBLANK,(struct IORequest *)TimerRequest,0)) != 0) Quit(1);
  924.  
  925.   if ((SoundMsgPort = CreateMsgPort()) == 0) Quit(1);
  926.  
  927.   if ((FileRequester = AllocAslRequestTags(ASL_FileRequest,
  928.     ASLFR_Window,Window,
  929.     ASLFR_SleepWindow,TRUE,
  930.     ASLFR_RejectIcons,TRUE,TAG_DONE)) == 0) Quit(1);
  931.  
  932.   if (RastPort->BitMap->Depth == 1)
  933.   {
  934.     RevForeColour = 0;
  935.     RevBackColour = 1;
  936.     InputColour = 1;
  937.   }
  938.  
  939.   EmphasisStyle = MoreFrotzPrefs.Flags & PREFS_ITALIC ?
  940.     FSF_ITALIC : FSF_UNDERLINED;
  941.  
  942.   option_left_margin = MoreFrotzPrefs.LeftMargin;
  943.   option_right_margin = MoreFrotzPrefs.RightMargin;
  944.  
  945.   if (h_version == V3)
  946.   {
  947.     h_config |= CONFIG_SPLITSCREEN;
  948.     h_config |= CONFIG_PROPORTIONAL;
  949.     if (user_tandy_bit != -1) h_config |= CONFIG_TANDY;
  950.     if (h_flags & OLD_SOUND_FLAG)
  951.     {
  952.       if (InitializeSound() == 0)
  953.       {
  954.     ResetSound();
  955.     h_flags &= ~OLD_SOUND_FLAG;
  956.       }
  957.     }
  958.   }
  959.   if (h_version >= V4)
  960.   {
  961.     h_config |= CONFIG_BOLDFACE;
  962.     h_config |= CONFIG_EMPHASIS;
  963.     h_config |= CONFIG_FIXED;
  964.     h_config |= CONFIG_TIMEDINPUT;
  965.     if (h_flags & SOUND_FLAG)
  966.     {
  967.       if (InitializeSound() == 0)
  968.       {
  969.     ResetSound();
  970.     h_flags &= ~SOUND_FLAG;
  971.       }
  972.     }
  973.   }
  974.   if (h_version >= V5)
  975.   {
  976.     if (UsingColour)
  977.       h_config |= CONFIG_COLOUR;
  978.     if (h_flags & UNDO_FLAG)
  979.     {
  980.       if (option_undo_slots == 0) h_flags &= ~UNDO_FLAG;
  981.     }
  982.     if (h_flags & COLOUR_FLAG)
  983.     {
  984.       if (UsingColour == 0) h_flags &= ~COLOUR_FLAG;
  985.     }
  986.     LoadGraphicsFile();
  987.   }
  988.   if (h_version == V6)
  989.   {
  990.     h_config |= CONFIG_PICTURES;
  991.     h_flags &= ~MENU_FLAG;
  992.   }
  993.  
  994.   if (h_version == V6)
  995.   {
  996.     h_default_foreground = WHITE_COLOUR;
  997.     h_default_background = BLACK_COLOUR;
  998.   }
  999.   else
  1000.   {
  1001.     h_default_foreground = 1;
  1002.     h_default_background = 1;
  1003.   }
  1004.   SetScreenDimensions();
  1005.   h_interpreter_number = INTERP_AMIGA;
  1006.   h_interpreter_version = h_version != V6 ? 'C' : 3;
  1007.  
  1008.   PreviousRows = h_screen_rows;
  1009. }
  1010.  
  1011. /*
  1012.  * os_more_prompt
  1013.  *
  1014.  * Display a MORE prompt, wait for a keypress and remove the MORE
  1015.  * prompt from the screen.
  1016.  *
  1017.  */
  1018.  
  1019. void os_more_prompt (void)
  1020. {
  1021. int saved_font;
  1022. int saved_style;
  1023. int saved_x,saved_y;
  1024. int new_x,new_y;
  1025.  
  1026.   FlushText();
  1027.  
  1028.   saved_font = current_font;
  1029.   saved_style = current_style;
  1030.  
  1031.   os_set_font(TEXT_FONT);
  1032.   os_set_text_style(0);
  1033.  
  1034.   GetCursorPos(&saved_y,&saved_x);
  1035.   os_display_string("[MORE]");
  1036.   os_read_key(0,1);
  1037.  
  1038.   GetCursorPos(&new_y,&new_x);
  1039.   os_erase_area(new_y,saved_x,new_y+h_font_height,new_x);
  1040.   os_set_cursor(saved_y,saved_x);
  1041.   os_set_font(saved_font);
  1042.   if (saved_style != 0) os_set_text_style(saved_style);
  1043. }
  1044.  
  1045. /*
  1046.  * os_prepare_sample
  1047.  *
  1048.  * Load the given sample from the disk.
  1049.  *
  1050.  */
  1051.  
  1052. void os_prepare_sample (int number)
  1053. {
  1054.   if (CurrentSample == number) return;
  1055.   os_finish_with_sample();
  1056.  
  1057. BPTR sound_data_lock;
  1058. BPTR sound_data_file;
  1059. unsigned long sample_length;
  1060. struct FileInfoBlock *sound_data_fib;
  1061. int i;
  1062.  
  1063.   sound_data_lock = LockSoundData(number);
  1064.   if (sound_data_lock)
  1065.   {
  1066.     if (sound_data_fib = AllocDosObject(DOS_FIB,0))
  1067.     {
  1068.       Examine(sound_data_lock,sound_data_fib);
  1069.       sample_length = sound_data_fib->fib_Size;
  1070.       FreeDosObject(DOS_FIB,sound_data_fib);
  1071.  
  1072.       if (SampleMemory = AllocVec(sample_length,MEMF_CHIP))
  1073.       {
  1074.     if (sound_data_file = OpenFromLock(sound_data_lock))
  1075.     {
  1076.       Read(sound_data_file,SampleMemory,sample_length);
  1077.       Close(sound_data_file);
  1078.  
  1079.       SampleHeader = (struct SampleHeader *)SampleMemory;
  1080.       if (SampleUnsigned)
  1081.       {
  1082.         for (i = 0; i < SampleHeader->SampleLength; i++)
  1083.           *(SampleMemory+sizeof(struct SampleHeader)+i) ^= 0x80;
  1084.       }
  1085.     }
  1086.       }
  1087.     }
  1088.     UnLock(sound_data_lock);
  1089.   }
  1090.  
  1091.   if (SampleMemory == 0) return;
  1092.   CurrentSample = number;
  1093. }
  1094.  
  1095. /*
  1096.  * os_process_arguments
  1097.  *
  1098.  * Handle command line switches. Some variables may be set to activate
  1099.  * special features of Frotz:
  1100.  *
  1101.  *     option_attribute_assignment
  1102.  *     option_attribute_testing
  1103.  *     option_context_lines
  1104.  *     option_object_locating
  1105.  *     option_object_movement
  1106.  *     option_left_margin
  1107.  *     option_right_margin
  1108.  *     option_ignore_errors
  1109.  *     option_piracy
  1110.  *     option_undo_slots
  1111.  *     option_expand_abbreviations
  1112.  *     option_script_cols
  1113.  *
  1114.  * The global pointer "story_name" is set to the story file name.
  1115.  *
  1116.  */
  1117.  
  1118. void os_process_arguments (int argc, char *argv[])
  1119. {
  1120.   if (IntuitionBase->lib_Version < 37) exit(0);
  1121.   LoadPreferences(1);
  1122.  
  1123. int num;
  1124. int c;
  1125. extern char GameFilename[];
  1126.  
  1127.   do
  1128.   {
  1129.     optarg = 0;
  1130.     c = getopt(argc,argv,"aAc:il:oOpr:s:S:tu:Wx");
  1131.  
  1132.     if (optarg != 0) num = atoi(optarg);
  1133.  
  1134.     switch (c)
  1135.     {
  1136.       case 'W': GetGameFilename();
  1137.         story_name = GameFilename;
  1138.         break;
  1139.       case 'a': option_attribute_assignment = 1;
  1140.         break;
  1141.       case 'A': option_attribute_testing = 1;
  1142.         break;
  1143.       case 'c': option_context_lines = num;
  1144.         break;
  1145.       case 'i': option_ignore_errors = 1;
  1146.         break;
  1147.       case 'l': option_left_margin = num;
  1148.         if (option_left_margin > 0)
  1149.           MoreFrotzPrefs.LeftMargin = option_left_margin;
  1150.         else
  1151.           option_left_margin = 0;
  1152.         break;
  1153.       case 'o': option_object_movement = 1;
  1154.         break;
  1155.       case 'O': option_object_locating = 1;
  1156.         break;
  1157.       case 'p': option_piracy = 1;
  1158.         break;
  1159.       case 'r': option_right_margin = num;
  1160.         if (option_right_margin > 0)
  1161.           MoreFrotzPrefs.RightMargin = option_right_margin;
  1162.         else
  1163.           option_right_margin = 0;
  1164.         break;
  1165.       case 's': user_random_seed = num;
  1166.         break;
  1167.       case 'S': option_script_cols = num;
  1168.         break;
  1169.       case 't': user_tandy_bit = 1;
  1170.         break;
  1171.       case 'u': option_undo_slots = num;
  1172.         break;
  1173.       case 'x': option_expand_abbreviations = 1;
  1174.         break;
  1175.     }
  1176.   }
  1177.   while (c != EOF);
  1178.  
  1179.   if (optind != argc-1 && story_name == 0)
  1180.   {
  1181.     puts(INFORMATION);
  1182.     DeleteList(&SearchDirs,1,0);
  1183.     DeleteList(&ExcludeDirs,1,0);
  1184.     DeleteList(&GamesList,1,0);
  1185.     exit(1);
  1186.   }
  1187.  
  1188.   if (story_name == 0) story_name = argv[optind];
  1189.   LoadPreferences(0);
  1190.  
  1191. BPTR lock;
  1192. extern char save_name[];
  1193. extern char script_name[];
  1194. extern char command_name[];
  1195. extern char auxilary_name[];
  1196. char *file_name;
  1197. char *extension;
  1198.  
  1199.   if (lock = Lock(story_name,ACCESS_READ))
  1200.   {
  1201.     NameFromLock(lock,save_name,MAX_FILE_NAME);
  1202.     UnLock(lock);
  1203.   }
  1204.   else strcpy(save_name,story_name);
  1205.   file_name = FilePart(save_name);
  1206.   extension = strrchr(save_name,'.');
  1207.   if (extension > file_name) *extension = 0;
  1208.  
  1209.   strcpy(script_name,FilePart(save_name));
  1210.   strcpy(command_name,save_name);
  1211.   strcpy(auxilary_name,save_name);
  1212.  
  1213.   strcat(save_name,".Save");
  1214.   strcat(script_name,".Script");
  1215.   strcat(command_name,".Record");
  1216.   strcat(auxilary_name,".Aux");
  1217. }
  1218.  
  1219. /*
  1220.  * os_read_line
  1221.  *
  1222.  * Read a line of input from the keyboard into a buffer. The buffer
  1223.  * may already be primed with some text. In this case, the "initial"
  1224.  * text is already displayed on the screen. After the input action
  1225.  * is complete, the function returns with the terminating key value.
  1226.  * The length of the input should not exceed "max" characters plus
  1227.  * an extra 0 terminator.
  1228.  *
  1229.  * Terminating keys are the return key (13) and all function keys
  1230.  * (see the Specification of the Z-machine) which are accepted by
  1231.  * the is_terminator function. Mouse clicks behave like function
  1232.  * keys except that the mouse position is stored in global variables
  1233.  * "mouse_x" and "mouse_y" (top left coordinates are (1,1)).
  1234.  *
  1235.  * Furthermore, Frotz introduces some special terminating keys:
  1236.  *
  1237.  *     ZC_HKEY_PLAYBACK (Alt-P)
  1238.  *     ZC_HKEY_RECORD (Alt-R)
  1239.  *     ZC_HKEY_SEED (Alt-S)
  1240.  *     ZC_HKEY_UNDO (Alt-U)
  1241.  *     ZC_HKEY_RESTART (Alt-N, "new game")
  1242.  *     ZC_HKEY_QUIT (Alt-X, "exit game")
  1243.  *     ZC_HKEY_DEBUG (Alt-D)
  1244.  *     ZC_HKEY_HELP (Alt-H)
  1245.  *
  1246.  * If the timeout argument is not zero, the input gets interrupted
  1247.  * after timeout/10 seconds (and the return value is 0).
  1248.  *
  1249.  * The complete input line including the cursor must fit in "width"
  1250.  * screen units.
  1251.  *
  1252.  * The function may be called once again to continue after timeouts,
  1253.  * misplaced mouse clicks or hot keys. In this case the "continued"
  1254.  * flag will be set. This information can be useful if the interface
  1255.  * implements input line history.
  1256.  *
  1257.  * The screen is not scrolled after the return key was pressed. The
  1258.  * cursor is at the end of the input line when the function returns.
  1259.  *
  1260.  * Since Frotz 2.2 the helper function "completion" can be called
  1261.  * to implement word completion (similar to tcsh under Unix).
  1262.  *
  1263.  */
  1264.  
  1265. zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued)
  1266. {
  1267. int c, pos;
  1268. int inputting = 1;
  1269. unsigned long saved_pen;
  1270. zchar extension[10];
  1271. UWORD qualifier;
  1272.  
  1273.   cursor_state = 1;
  1274.   pos = strlen(buf);
  1275.   DrawCursor(*(buf+pos));
  1276.   InputMax1 = RastPort->cp_x+width;
  1277.   InputMax2 = MIN(InputMax1,Window->Width-Window->BorderRight);
  1278.   saved_pen = RastPort->FgPen;
  1279.   if (cwin == 0)
  1280.   {
  1281.     if (UsingColour < 2) SetAPen(RastPort,InputColour);
  1282.   }
  1283.  
  1284.   StartTimer(timeout);
  1285.   while (inputting)
  1286.   {
  1287.     LimitWindow(1,TextLength(RastPort,buf+pos,strlen(buf+pos)));
  1288.     c = GetKey(&qualifier);
  1289.     LimitWindow(0,0);
  1290.  
  1291.     switch (c)
  1292.     {
  1293.       case 27:        /* Escape */
  1294.     break;
  1295.  
  1296.       case 264:        /* Window Sizing */
  1297.     RedrawLine(buf,&pos,max);
  1298.     break;
  1299.  
  1300.       case 261:        /* Tab */
  1301.     if (pos == strlen(buf))
  1302.     {
  1303.       if (completion(buf,extension) == 0)
  1304.       {
  1305.       zchar *tbuf;
  1306.  
  1307.         if (tbuf = malloc(strlen(buf)+strlen(extension)+1))
  1308.         {
  1309.           strcpy(tbuf,buf);
  1310.           strcat(tbuf,extension);
  1311.           PutIntoBuffer(buf,tbuf,&pos,max);
  1312.           free(tbuf);
  1313.         }
  1314.       }
  1315.       else os_beep(1);
  1316.     }
  1317.     break;
  1318.       case ZC_BACKSPACE:    /* Backspace */
  1319.     if (pos > 0)
  1320.     {
  1321.     int deleted;
  1322.  
  1323.       DrawCursor(*(buf+pos));
  1324.       deleted = *(buf+pos-1);
  1325.       memmove(buf+pos-1,buf+pos,strlen(buf)-pos+1);
  1326.       MoveTextRow(-CharLength(deleted),InputMax2);
  1327.       Move(RastPort,RastPort->cp_x-CharLength(deleted),RastPort->cp_y);
  1328.       pos--;
  1329.       DrawCursor(*(buf+pos));
  1330.     }
  1331.         break;
  1332.  
  1333.       case 260:            /* Delete */
  1334.     if (pos < strlen(buf))
  1335.     {
  1336.     int deleted;
  1337.  
  1338.       DrawCursor(*(buf+pos));
  1339.       deleted = *(buf+pos);
  1340.       memmove(buf+pos,buf+pos+1,strlen(buf)-pos);
  1341.       Move(RastPort,RastPort->cp_x+CharLength(deleted),RastPort->cp_y);
  1342.       MoveTextRow(-CharLength(deleted),InputMax2);
  1343.       Move(RastPort,RastPort->cp_x-CharLength(deleted),RastPort->cp_y);
  1344.       DrawCursor(*(buf+pos));
  1345.     }
  1346.         break;
  1347.  
  1348.       case ZC_ARROW_LEFT:    /* Cursor Left */
  1349.     if (pos > 0)
  1350.     {
  1351.       if (qualifier & QUALIFIER_SHIFT)
  1352.       {
  1353.         DrawCursor(*(buf+pos));
  1354.         CursorLeftEnd(buf,&pos);
  1355.         DrawCursor(*(buf+pos));
  1356.       }
  1357.       else
  1358.       {
  1359.         DrawCursor(*(buf+pos--));
  1360.         Move(RastPort,RastPort->cp_x-CharLength(*(buf+pos)),RastPort->cp_y);
  1361.         DrawCursor(*(buf+pos));
  1362.       }
  1363.     }
  1364.     break;
  1365.  
  1366.       case ZC_ARROW_RIGHT:    /* Cursor Right */
  1367.     if (pos < strlen(buf))
  1368.     {
  1369.       if (qualifier & QUALIFIER_SHIFT)
  1370.       {
  1371.         DrawCursor(*(buf+pos));
  1372.         CursorRightEnd(buf,&pos);
  1373.         DrawCursor(*(buf+pos));
  1374.       }
  1375.       else
  1376.       {
  1377.         DrawCursor(*(buf+pos));
  1378.         Move(RastPort,RastPort->cp_x+CharLength(*(buf+pos)),RastPort->cp_y);
  1379.         pos++;
  1380.         DrawCursor(*(buf+pos));
  1381.       }
  1382.     }
  1383.     break;
  1384.  
  1385.       case ZC_ARROW_UP:        /* Cursor Up */
  1386.     if ((cwin != 0) || (qualifier & QUALIFIER_ALT))
  1387.     {
  1388.       if (is_terminator(c) != 0)
  1389.       {
  1390.         StopTimer();
  1391.         return Terminate(buf,pos,c,saved_pen);
  1392.       }
  1393.     }
  1394.     else
  1395.     {
  1396.       if (qualifier & QUALIFIER_SHIFT)
  1397.       {
  1398.         HistoryPosition = 0;
  1399.         while ((*(History+HistoryPosition) == 0) && (HistoryPosition < HISTORY_LINES))
  1400.           HistoryPosition++;
  1401.         PutIntoBuffer(buf,HistoryPosition == HISTORY_LINES ?
  1402.         (unsigned char *)"" : *(History+HistoryPosition),&pos,max);
  1403.       }
  1404.       else
  1405.       {
  1406.         if ((HistoryPosition > 0) && (*(History+HistoryPosition-1) != 0))
  1407.         {
  1408.           HistoryPosition--;
  1409.           PutIntoBuffer(buf,*(History+HistoryPosition),&pos,max);
  1410.         }
  1411.       }
  1412.     }
  1413.     break;
  1414.  
  1415.       case ZC_ARROW_DOWN:    /* Cursor Down */
  1416.     if ((cwin != 0) || (qualifier & QUALIFIER_ALT))
  1417.     {
  1418.       if (is_terminator(c) != 0)
  1419.       {
  1420.         StopTimer();
  1421.         return Terminate(buf,pos,c,saved_pen);
  1422.       }
  1423.     }
  1424.     else
  1425.     {
  1426.       if (qualifier & QUALIFIER_SHIFT)
  1427.       {
  1428.         HistoryPosition = HISTORY_LINES;
  1429.         PutIntoBuffer(buf,"",&pos,max);
  1430.       }
  1431.       else
  1432.       {
  1433.         if ((HistoryPosition < HISTORY_LINES-1) && (*(History+HistoryPosition+1) != 0))
  1434.         {
  1435.           HistoryPosition++;
  1436.           PutIntoBuffer(buf,
  1437.         HistoryPosition == HISTORY_LINES ?
  1438.           (unsigned char *)"" : *(History+HistoryPosition),&pos,max);
  1439.         }
  1440.         else
  1441.         {
  1442.           HistoryPosition = HISTORY_LINES;
  1443.           PutIntoBuffer(buf,"",&pos,max);
  1444.         }
  1445.       }
  1446.     }
  1447.     break;
  1448.  
  1449.       default:
  1450.     if (c >= 2000)        /* Menus */
  1451.     {
  1452.       PutIntoBuffer(buf,GTMENUITEM_USERDATA(ItemAddress(Menus,c-2000)),&pos,max);
  1453.       c = ZC_RETURN;
  1454.     }
  1455.  
  1456.     if ((c >= ZC_ASCII_MIN && c <= ZC_ASCII_MAX) || (c >= ZC_LATIN1_MIN && c <= ZC_LATIN1_MAX))
  1457.     {
  1458.       if ((strlen(buf) < max) && (FitTextLine(buf+pos,c)))
  1459.       {
  1460.         memmove(buf+pos+1,buf+pos,strlen(buf)-pos+1);
  1461.         *(buf+pos) = c;
  1462.  
  1463.         pos++;
  1464.         DrawCursor(*(buf+pos));
  1465.         MoveTextRow(CharLength(c),InputMax2);
  1466.         os_display_char(c);
  1467.         DrawCursor(*(buf+pos));
  1468.       }
  1469.     }
  1470.     else
  1471.     {
  1472.       if (is_terminator(c) != 0)
  1473.       {
  1474.         StopTimer();
  1475.         return Terminate(buf,pos,c,saved_pen);
  1476.       }
  1477.     }
  1478.     break;
  1479.     }
  1480.   }
  1481. }
  1482.  
  1483. /*
  1484.  * os_read_key
  1485.  *
  1486.  * Read a single character from the keyboard (or a mouse click) and
  1487.  * return it. Input aborts after timeout/10 seconds.
  1488.  *
  1489.  */
  1490.  
  1491. zchar os_read_key (int timeout, bool cursor)
  1492. {
  1493. int key = 0;
  1494.  
  1495.   cursor_state = (cursor) ? 1 : 0;
  1496.   DrawCursor(0);
  1497.  
  1498.   do
  1499.   {
  1500.     StartTimer(timeout);
  1501.     LimitWindow(1,0);
  1502.     if (key == 264) DrawCursor(0);        /* Window Sizing */
  1503.     key = GetKey(0);
  1504.     LimitWindow(0,0);
  1505.     StopTimer();
  1506.   }
  1507.   while (key >= 256);
  1508.  
  1509.   DrawCursor(0);
  1510.   last_text_out = 0;
  1511.   return (key);
  1512. }
  1513.  
  1514. /*
  1515.  * os_reset_screen
  1516.  *
  1517.  * Reset the screen before the program ends.
  1518.  *
  1519.  */
  1520.  
  1521. void os_reset_screen (void)
  1522. {
  1523.   FlushText();
  1524.  
  1525.   if (last_text_out != 0)
  1526.   {
  1527.     os_set_font(TEXT_FONT);
  1528.     os_set_text_style(0);
  1529.     screen_new_line();
  1530.     os_display_string("[Hit any key to exit.]");
  1531.     os_read_key(0,1);
  1532.   }
  1533.  
  1534.   CloseDisplay();
  1535.   DeleteList(&SearchDirs,1,0);
  1536.   DeleteList(&ExcludeDirs,1,0);
  1537.   DeleteList(&GamesList,1,0);
  1538. }
  1539.  
  1540. /*
  1541.  * os_scroll_area
  1542.  *
  1543.  * Scroll a rectangular area of the screen up (units > 0) or down
  1544.  * (units < 0) and fill the empty space with the current background
  1545.  * colour. Top left coordinates are (1,1). The cursor stays put.
  1546.  *
  1547.  */
  1548.  
  1549. void os_scroll_area (int top, int left, int bottom, int right, int units)
  1550. {
  1551.   FlushText();
  1552.   if (units > 0)
  1553.   {
  1554.     ClipBlit(RastPort,
  1555.       Window->BorderLeft+left-1,
  1556.       Window->BorderTop+top-1+units,
  1557.       RastPort,
  1558.       Window->BorderLeft+left-1,
  1559.       Window->BorderTop+top-1,
  1560.       right-left+1,bottom-top+1-units,0xC0);
  1561.     SafeRectFill(RastPort,
  1562.       Window->BorderLeft+left-1,
  1563.       Window->BorderTop+bottom-units,
  1564.       Window->BorderLeft+right-1,
  1565.       Window->BorderTop+bottom-1,
  1566.       UsingColour != 0 ? RastPort->BgPen : BackColour);
  1567.   }
  1568. }
  1569.  
  1570. /*
  1571.  * os_set_colour
  1572.  *
  1573.  * Set the foreground and background colours which can be:
  1574.  *
  1575.  *     1
  1576.  *     BLACK_COLOUR
  1577.  *     RED_COLOUR
  1578.  *     GREEN_COLOUR
  1579.  *     YELLOW_COLOUR
  1580.  *     BLUE_COLOUR
  1581.  *     MAGENTA_COLOUR
  1582.  *     CYAN_COLOUR
  1583.  *     WHITE_COLOUR
  1584.  *
  1585.  *     Amiga only:
  1586.  *
  1587.  *     LIGHTGREY_COLOUR
  1588.  *     MEDIUMGREY_COLOUR
  1589.  *     DARKGREY_COLOUR
  1590.  *
  1591.  * There may be more colours in the range from 16 to 255; see the
  1592.  * remarks about os_peek_colour.
  1593.  *
  1594.  */
  1595.  
  1596. void os_set_colour (int new_foreground, int new_background)
  1597. {
  1598.   FlushText();
  1599.  
  1600.   switch (UsingColour)
  1601.   {
  1602.     case 0:
  1603.       SetAPen(RastPort,ForeColour);
  1604.       SetBPen(RastPort,BackColour);
  1605.       if (GfxType == GFX_IBM_CGA)
  1606.       {
  1607.     if (new_foreground == BLACK_COLOUR) SetAPen(RastPort,1);
  1608.     if (new_foreground == WHITE_COLOUR) SetAPen(RastPort,2);
  1609.     if (new_background == BLACK_COLOUR) SetBPen(RastPort,1);
  1610.     if (new_background == WHITE_COLOUR) SetBPen(RastPort,2);
  1611.       }
  1612.       break;
  1613.     case 1:
  1614.       if (new_foreground != 1)
  1615.       {
  1616.     if (UsePenTable)
  1617.       SetAPen(RastPort,ZMachinePens[new_foreground-BLACK_COLOUR]);
  1618.     else
  1619.       SetAPen(RastPort,new_foreground-BLACK_COLOUR+4);
  1620.       }
  1621.       else SetAPen(RastPort,ForeColour);
  1622.  
  1623.       if (new_background != 1)
  1624.       {
  1625.     if (UsePenTable)
  1626.       SetBPen(RastPort,ZMachinePens[new_background-BLACK_COLOUR]);
  1627.     else
  1628.       SetBPen(RastPort,new_background-BLACK_COLOUR+4);
  1629.       }
  1630.       else SetBPen(RastPort,BackColour);
  1631.       break;
  1632.     case 2:
  1633.       if (new_foreground == 1)
  1634.     new_foreground = WHITE_COLOUR;
  1635.       if (new_background == 1)
  1636.     new_background = BLACK_COLOUR;
  1637.  
  1638.       if (UsePenTable)
  1639.       {
  1640.     SetAPen(RastPort,ZMachinePens[new_foreground-BLACK_COLOUR]);
  1641.     SetBPen(RastPort,ZMachinePens[new_background-BLACK_COLOUR]);
  1642.       }
  1643.       else
  1644.       {
  1645.     SetAPen(RastPort,new_foreground-BLACK_COLOUR+4);
  1646.     SetBPen(RastPort,new_background-BLACK_COLOUR+4);
  1647.       }
  1648.  
  1649.       if (cwin == 0)
  1650.       {
  1651.     CustomColours[0] = CustomColours[RastPort->BgPen];
  1652.     SetColourScheme(1);
  1653.       }
  1654.       break;
  1655.     case 3:
  1656.       if (new_foreground == 1)
  1657.     new_foreground = h_default_foreground;
  1658.       if (new_background == 1)
  1659.     new_background = h_default_background;
  1660.       SetAPen(RastPort,UsePenTable ? ZMachinePens[1] : 1);
  1661.       SetBPen(RastPort,UsePenTable ? ZMachinePens[0] : 0);
  1662.       if (cwin == 0)
  1663.       {
  1664.     if (new_foreground < 16)
  1665.       CustomColours[1] = ZColours[new_foreground-BLACK_COLOUR];
  1666.     if (new_background < 16)
  1667.       CustomColours[0] = ZColours[new_background-BLACK_COLOUR];
  1668.     SetColourScheme(1);
  1669.     if (UsePenTable)
  1670.     {
  1671.       SetRGB4(&(Window->WScreen->ViewPort),ZMachinePens[0],
  1672.         (CustomColours[0]&0x0F00)>>8,
  1673.         (CustomColours[0]&0x00F0)>>4,
  1674.         (CustomColours[0]&0x000F));
  1675.       SetRGB4(&(Window->WScreen->ViewPort),ZMachinePens[1],
  1676.         (CustomColours[1]&0x0F00)>>8,
  1677.         (CustomColours[1]&0x00F0)>>4,
  1678.         (CustomColours[1]&0x000F));
  1679.     }
  1680.       }
  1681.       else
  1682.       {
  1683.     if (new_foreground < 16)
  1684.     {
  1685.       if (ZColours[new_foreground-BLACK_COLOUR] == CustomColours[0])
  1686.         SetAPen(RastPort,UsePenTable ? ZMachinePens[0] : 0);
  1687.       if (ZColours[new_foreground-BLACK_COLOUR] == CustomColours[1])
  1688.         SetAPen(RastPort,UsePenTable ? ZMachinePens[1] : 1);
  1689.     }
  1690.     else SetAPen(RastPort,new_foreground-16);
  1691.     if (new_background < 16)
  1692.     {
  1693.       if (ZColours[new_background-BLACK_COLOUR] == CustomColours[0])
  1694.         SetBPen(RastPort,UsePenTable ? ZMachinePens[0] : 0);
  1695.       if (ZColours[new_background-BLACK_COLOUR] == CustomColours[1])
  1696.         SetBPen(RastPort,UsePenTable ? ZMachinePens[1] : 1);
  1697.     }
  1698.     else SetBPen(RastPort,new_background-16);
  1699.       }
  1700.       break;
  1701.   }
  1702. }
  1703.  
  1704. /*
  1705.  * os_set_cursor
  1706.  *
  1707.  * Place the text cursor at the given coordinates. Top left is (1,1).
  1708.  *
  1709.  */
  1710.  
  1711. void os_set_cursor (int row, int col)
  1712. {
  1713.   FlushText();
  1714.   if (row > h_screen_height-h_font_height+1)
  1715.     row = h_screen_height-h_font_height+1;
  1716.   if (col > h_screen_width-h_font_width+1)
  1717.     col = h_screen_width-h_font_width+1;
  1718.   Move(RastPort,Window->BorderLeft+col-1,Window->BorderTop+row-1);
  1719. }
  1720.  
  1721. /*
  1722.  * os_set_font
  1723.  *
  1724.  * Set the font for text output. The interpreter takes care not to
  1725.  * choose fonts which aren't supported by the interface.
  1726.  *
  1727.  */
  1728.  
  1729. void os_set_font (int new_font)
  1730. {
  1731.   FlushText();
  1732.   current_font = new_font;
  1733.   os_set_text_style(current_style);
  1734. }
  1735.  
  1736. /*
  1737.  * os_set_text_style
  1738.  *
  1739.  * Set the current text style. Following flags can be set:
  1740.  *
  1741.  *     REVERSE_STYLE
  1742.  *     BOLDFACE_STYLE
  1743.  *     EMPHASIS_STYLE (aka underline aka italics)
  1744.  *     FIXED_WIDTH_STYLE
  1745.  *
  1746.  */
  1747.  
  1748. void os_set_text_style (int new_style)
  1749. {
  1750.   FlushText();
  1751.   current_style = new_style;
  1752.  
  1753.   if (current_font == FIXED_WIDTH_FONT || new_style & FIXED_WIDTH_STYLE)
  1754.     SetFont(RastPort,FixedFont);
  1755.   else
  1756.     SetFont(RastPort,TextFont);
  1757.  
  1758.   if ((story_id != BEYOND_ZORK) && (UsingColour == 0))
  1759.   {
  1760.     SetAPen(RastPort,ForeColour);
  1761.     SetBPen(RastPort,BackColour);
  1762.   }
  1763.   else SetDrMd(RastPort,JAM2);
  1764.   SetSoftStyle(RastPort,FS_NORMAL,AskSoftStyle(RastPort));
  1765.  
  1766.   if (new_style & REVERSE_STYLE)
  1767.   {
  1768.     if ((story_id != BEYOND_ZORK) && (UsingColour == 0))
  1769.     {
  1770.       SetAPen(RastPort,RevForeColour);
  1771.       SetBPen(RastPort,RevBackColour);
  1772.     }
  1773.     else SetDrMd(RastPort,JAM2|INVERSVID);
  1774.   }
  1775.  
  1776.   if (new_style & BOLDFACE_STYLE)
  1777.   {
  1778.     while ((RastPort->AlgoStyle & FSF_BOLD) == 0)
  1779.       SetSoftStyle(RastPort,RastPort->AlgoStyle|FSF_BOLD,AskSoftStyle(RastPort));
  1780.   }
  1781.  
  1782.   if (new_style & EMPHASIS_STYLE)
  1783.   {
  1784.     while ((RastPort->AlgoStyle & EmphasisStyle) == 0)
  1785.       SetSoftStyle(RastPort,RastPort->AlgoStyle|EmphasisStyle,
  1786.       AskSoftStyle(RastPort));
  1787.   }
  1788. }
  1789.  
  1790. /*
  1791.  * os_start_sample
  1792.  *
  1793.  * Play the given sample at the given volume (ranging from 1 to 8 and
  1794.  * 255 meaning a default volume). The sound is played once or several
  1795.  * times in the background (255 meaning forever). The end_of_sound
  1796.  * function is called as soon as the sound finishes.
  1797.  *
  1798.  */
  1799.  
  1800. void os_start_sample (int number, int volume, int repeats)
  1801. {
  1802.   os_stop_sample();
  1803.   os_prepare_sample(number);
  1804.  
  1805.   if (CurrentSample == 0) return;
  1806.  
  1807. unsigned long rate;
  1808.  
  1809.   rate = (GfxBase->DisplayFlags&PAL ? 3546895 : 3579545) / SampleHeader->Frequency;
  1810.  
  1811.   SoundRequest->ioa_Request.io_Command = CMD_STOP;
  1812.   BeginIO(SoundRequest);
  1813.   WaitForMsg(SoundMsgPort);
  1814.  
  1815.   SoundLeftRequest->ioa_Request.io_Command = CMD_WRITE;
  1816.   SoundLeftRequest->ioa_Request.io_Flags = ADIOF_PERVOL;
  1817.   SoundLeftRequest->ioa_Period = rate;
  1818.   SoundLeftRequest->ioa_Volume = volume * 8;
  1819.   SoundLeftRequest->ioa_Cycles = repeats;
  1820.   SoundLeftRequest->ioa_Data = SampleMemory+sizeof(struct SampleHeader);
  1821.   SoundLeftRequest->ioa_Length = SampleHeader->SampleLength;
  1822.   if (SampleUnsigned)
  1823.   {
  1824.     SoundLeftRequest->ioa_Data += MAC_OFFSET;
  1825.     SoundLeftRequest->ioa_Length -= (MAC_OFFSET*2);
  1826.   }
  1827.   BeginIO(SoundLeftRequest);
  1828.  
  1829.   SoundRightRequest->ioa_Request.io_Command = CMD_WRITE;
  1830.   SoundRightRequest->ioa_Request.io_Flags = ADIOF_PERVOL;
  1831.   SoundRightRequest->ioa_Period = rate;
  1832.   SoundRightRequest->ioa_Volume = volume * 8;
  1833.   SoundRightRequest->ioa_Cycles = repeats;
  1834.   SoundRightRequest->ioa_Data = SampleMemory+sizeof(struct SampleHeader);
  1835.   SoundRightRequest->ioa_Length = SampleHeader->SampleLength;
  1836.   if (SampleUnsigned)
  1837.   {
  1838.     SoundRightRequest->ioa_Data += MAC_OFFSET;
  1839.     SoundRightRequest->ioa_Length -= (MAC_OFFSET*2);
  1840.   }
  1841.   BeginIO(SoundRightRequest);
  1842.  
  1843.   SoundRequest->ioa_Request.io_Command = CMD_START;
  1844.   BeginIO(SoundRequest);
  1845.   WaitForMsg(SoundMsgPort);
  1846.  
  1847.   SamplePlaying = 1;
  1848. }
  1849.  
  1850. /*
  1851.  * os_stop_sample
  1852.  *
  1853.  * Turn off the current sample.
  1854.  *
  1855.  */
  1856.  
  1857. void os_stop_sample (void)
  1858. {
  1859.   if (SoundOpenCode != 0) return;
  1860.  
  1861.   SoundLeftRequest->ioa_Request.io_Command = CMD_FLUSH;
  1862.   BeginIO(SoundLeftRequest);
  1863.   WaitForMsg(SoundMsgPort);
  1864.  
  1865.   SoundRightRequest->ioa_Request.io_Command = CMD_FLUSH;
  1866.   BeginIO(SoundRightRequest);
  1867.   WaitForMsg(SoundMsgPort);
  1868.  
  1869.   SamplePlaying = 0;
  1870. }
  1871.  
  1872. /*
  1873.  * os_string_width
  1874.  *
  1875.  * Calculate the length of a word in screen units. Apart from letters,
  1876.  * the word may contain special codes:
  1877.  *
  1878.  *    ZC_NEW_STYLE - next character is a new text style
  1879.  *    ZC_NEW_FONT  - next character is a new font
  1880.  *
  1881.  */
  1882.  
  1883. int os_string_width (const zchar *s)
  1884. {
  1885. int length,i,c;
  1886.  
  1887.   if (((TextFont->tf_Flags & FPF_PROPORTIONAL) == 0) && (TextFont->tf_XSize == FixedFont->tf_XSize))
  1888.   {
  1889.     length = 0;
  1890.     for (i = 0; s[i] != 0; i++)
  1891.     {
  1892.       c = (unsigned char) s[i];
  1893.       if ((c == ZC_NEW_STYLE) || (c == ZC_NEW_FONT)) i++;
  1894.       if (c == ZC_INDENT) length += 3;
  1895.       if (c == ZC_GAP) length += 2;
  1896.       if ((c >= ZC_ASCII_MIN && c <= ZC_ASCII_MAX) || (c >= ZC_LATIN1_MIN && c <= ZC_LATIN1_MAX))
  1897.     length++;
  1898.     }
  1899.     return length*TextWidth;
  1900.   }
  1901.   else
  1902.   {
  1903.     length = 0;
  1904.     for (i = 0; s[i] != 0; i++)
  1905.     {
  1906.       c = (unsigned char) s[i];
  1907.  
  1908.       if (c == ZC_INDENT)
  1909.       {
  1910.     *(LengthBuffer+length++) = ' ';
  1911.     *(LengthBuffer+length++) = ' ';
  1912.     c = ' ';
  1913.       }
  1914.       if (c == ZC_GAP)
  1915.       {
  1916.     *(LengthBuffer+length++) = ' ';
  1917.     c = ' ';
  1918.       }
  1919.  
  1920.       if ((c == ZC_NEW_STYLE) || (c == ZC_NEW_FONT))
  1921.       {
  1922.     i++;
  1923.       }
  1924.       else
  1925.       {
  1926.     if (c >= 32)
  1927.     {
  1928.       if (length < TEXTBUFFER_SIZE) *(LengthBuffer+length++) = c;
  1929.     }
  1930.       }
  1931.     }
  1932.     return TextLength(RastPort,LengthBuffer,length);
  1933.   }
  1934. }
  1935.  
  1936. /*
  1937.  * os_char_width
  1938.  *
  1939.  * Return the length of the character in screen units.
  1940.  *
  1941.  */
  1942.  
  1943. int os_char_width (zchar c)
  1944. {
  1945. char s[2];
  1946.  
  1947.   s[0] = c;
  1948.   s[1] = 0;
  1949.   return os_string_width(s);
  1950. }
  1951.  
  1952. /*
  1953.  * os_peek_colour
  1954.  *
  1955.  * Return the colour of the screen unit below the cursor. (If the
  1956.  * interface uses a text mode, it may return the background colour
  1957.  * of the character at the cursor position instead.) This is used
  1958.  * when text is printed on top of pictures. Note that this coulor
  1959.  * need not be in the standard set of Z-machine colours. To handle
  1960.  * this situation, Frotz entends the colour scheme: Colours above
  1961.  * 15 (and below 256) may be used by the interface to refer to non
  1962.  * standard colours. Of course, os_set_colour must be able to deal
  1963.  * with these colours.
  1964.  *
  1965.  */
  1966.  
  1967. int os_peek_colour (void)
  1968. {
  1969. ULONG pen,colour;
  1970. int i;
  1971.  
  1972.   pen = ReadPixel(RastPort,RastPort->cp_x,
  1973.     RastPort->cp_y+RastPort->TxBaseline);
  1974.   if (UsingColour == 3)
  1975.   {
  1976.     colour = GetRGB4(Window->WScreen->ViewPort.ColorMap,pen);
  1977.     if (pen < 2)
  1978.     {
  1979.       for (i = 0; i < 11; i++)
  1980.     if (colour == ZColours[i]) return i+BLACK_COLOUR;
  1981.     }
  1982.     return pen+16;
  1983.   }
  1984.   else
  1985.   {
  1986.     switch (pen)
  1987.     {
  1988.       case 0:
  1989.     return h_default_background;
  1990.       case 1:
  1991.     return BLACK_COLOUR;
  1992.       case 2:
  1993.     return WHITE_COLOUR;
  1994.       default:
  1995.     return h_default_foreground;
  1996.     }
  1997.   }
  1998. }
  1999.  
  2000. /*
  2001.  * os_picture_data
  2002.  *
  2003.  * Return true if the given picture is available. If so, store the
  2004.  * picture width and height in the appropriate variables. Picture
  2005.  * number 0 is a special case: Write the highest legal picture number
  2006.  * and the picture file release number into the height and width
  2007.  * variables respectively when this picture number is asked for.
  2008.  *
  2009.  */
  2010.  
  2011. int os_picture_data (int picture, int *height, int *width)
  2012. {
  2013. char *info;
  2014.  
  2015.   if (GfxMemory)
  2016.   {
  2017.     if (picture == 0)
  2018.     {
  2019.       *height = ByteSwap(GfxHeader->Images);
  2020.       *width = ByteSwap(GfxHeader->Version);
  2021.       return 1;
  2022.     }
  2023.     if (info = FindPicture(picture))
  2024.     {
  2025.       *height = ByteSwap(*(short *)(info+PIC_HEIGHT));
  2026.       *width = ByteSwap(*(short *)(info+PIC_WIDTH));
  2027.  
  2028.       if (GfxType == GFX_IBM_MCGA || GfxType == GFX_AMIGA)
  2029.     *width *= 2;
  2030.  
  2031.       return 1;
  2032.     }
  2033.   }
  2034.   *height = 0;
  2035.   *width = 0;
  2036.   return 0;
  2037. }
  2038.  
  2039. /*
  2040.  * os_draw_picture
  2041.  *
  2042.  * Display a picture at the given coordinates.
  2043.  *
  2044.  */
  2045.  
  2046. void os_draw_picture (int picture, int y, int x)
  2047. {
  2048. char *info;
  2049.  
  2050.   if (UsingColour == 0 && GfxType != GFX_IBM_CGA) return;
  2051.   if (GfxMemory == 0) return;
  2052.   if ((info = FindPicture(picture)) == 0) return;
  2053.   x += Window->BorderLeft-1;
  2054.   y += Window->BorderTop-1;
  2055.  
  2056. unsigned char buf[512];
  2057. long data, colour;
  2058. unsigned short code, prev_code, val;
  2059. short width, height, flags;
  2060. short count, bits, bits_per_code, bits_left, pos, iwidth;
  2061. int i, j, ypos = -1, alloc = 0, depth;
  2062. struct BitMap bitmap;
  2063. PLANEPTR mask;
  2064.  
  2065.   data = (long)((*(unsigned char *)(info+PIC_DATA))<<16)+
  2066.      (long)((*(unsigned char *)(info+PIC_DATA+1))<<8)+
  2067.      (long)(*(unsigned char *)(info+PIC_DATA+2));
  2068.   width = ByteSwap(*(short *)(info+PIC_WIDTH));
  2069.   height = ByteSwap(*(short *)(info+PIC_HEIGHT));
  2070.   flags = ByteSwap(*(short *)(info+PIC_FLAGS));
  2071.  
  2072.   if (GfxHeader->InfoSize >= 14)
  2073.   {
  2074.     colour = (long)((*(unsigned char *)(info+PIC_COLOUR))<<16)+
  2075.          (long)((*(unsigned char *)(info+PIC_COLOUR+1))<<8)+
  2076.          (long)(*(unsigned char *)(info+PIC_COLOUR+2));
  2077.     if (colour != 0)
  2078.     {
  2079.       count = *((unsigned char *)(GfxMemory+colour++));
  2080.       if (Screen)
  2081.       {
  2082.     for (i = 0; i < 14; i++)
  2083.     {
  2084.       CustomColours[2+i] =
  2085.         (((int)*((unsigned char *)(GfxMemory+colour))>>4)<<8)+
  2086.         (((int)*((unsigned char *)(GfxMemory+colour+1))>>4)<<4)+
  2087.         ((int)*((unsigned char *)(GfxMemory+colour+2))>>4);
  2088.       colour+=3;
  2089.     }
  2090.     LoadRGB4(&Screen->ViewPort,CustomColours,16);
  2091.       }
  2092.       else
  2093.       {
  2094.       ULONG r,g,b;
  2095.  
  2096.     for (i = 0; i < 14; i++)
  2097.     {
  2098.       r = (int)*((unsigned char *)(GfxMemory+colour))>>4;
  2099.       g = (int)*((unsigned char *)(GfxMemory+colour+1))>>4;
  2100.       b = (int)*((unsigned char *)(GfxMemory+colour+2))>>4;
  2101.       SetRGB4(&(Window->WScreen->ViewPort),ZMachinePens[2+i],r,g,b);
  2102.       colour+=3;
  2103.     }
  2104.       }
  2105.     }
  2106.   }
  2107.  
  2108.   if (GfxType == GFX_AMIGA) return;
  2109.   iwidth = width;
  2110.   if (GfxType == GFX_IBM_MCGA) iwidth *= 2;
  2111.  
  2112.   depth = UsePenTable ? 8 : 4;
  2113.   InitBitMap(&bitmap,depth,iwidth,height);
  2114.   for (i = 0; i < depth; i++)
  2115.   {
  2116.     if (bitmap.Planes[i] = AllocRaster(iwidth,height))
  2117.     {
  2118.       BltClear(bitmap.Planes[i],RASSIZE(iwidth,height),0);
  2119.       alloc++;
  2120.     }
  2121.   }
  2122.   if (mask = AllocRaster(iwidth,height))
  2123.   {
  2124.     BltClear(mask,RASSIZE(iwidth,height),0);
  2125.     alloc++;
  2126.   }
  2127.  
  2128.   if (alloc == depth+1)
  2129.   {
  2130.     bits_per_code = 9;
  2131.     bits_left = 0;
  2132.     pos = 9999;
  2133.  
  2134.     for (;;)
  2135.     {
  2136.       code = 0;
  2137.       i = bits_per_code;
  2138.       do
  2139.       {
  2140.     if (bits_left <= 0)
  2141.     {
  2142.       bits = *((unsigned char *)(GfxMemory+(data++)));
  2143.       bits_left = 8;
  2144.     }
  2145.     code |= (bits>>(8-bits_left))<<(bits_per_code-i);
  2146.     i -= bits_left;
  2147.     bits_left = -i;
  2148.       }
  2149.       while (i > 0);
  2150.  
  2151.       code &= 0xFFF>>(12-bits_per_code);
  2152.       if (code == 256)
  2153.       {
  2154.     bits_per_code = 9;
  2155.     count = 257;
  2156.     continue;
  2157.       }
  2158.       if (code == 257) break;
  2159.       val = code;
  2160.       i = 0;
  2161.       if (code == count)
  2162.       {
  2163.      val = prev_code;
  2164.     i = 1;
  2165.       }
  2166.       while (val > 255)
  2167.       {
  2168.     buf[i++] = TableVal[val-256];
  2169.     val = TableSeq[val-256];
  2170.       }
  2171.       buf[i] = val;
  2172.       if (code == count) buf[0] = val;
  2173.       TableVal[count-256] = val;
  2174.       TableSeq[count-256] = prev_code;
  2175.       if (++count == (1<<bits_per_code) && bits_per_code < 12)
  2176.     bits_per_code++;
  2177.  
  2178.       do
  2179.       {
  2180.       int bitpos;
  2181.  
  2182.     if (pos >= width)
  2183.     {
  2184.       ypos++;
  2185.       bitpos = ypos*bitmap.BytesPerRow;
  2186.       pos = 0;
  2187.     }
  2188.     val = buf[i--];
  2189.  
  2190.     if (GfxType == GFX_IBM_CGA)
  2191.     {
  2192.     int black,white;
  2193.  
  2194.       black = (UsingColour && Screen) ? 4 : 1;
  2195.       white = (UsingColour && Screen) ? WHITE_COLOUR-BLACK_COLOUR+4 : 2;
  2196.  
  2197.       if (flags & 1)
  2198.       {
  2199.         if (val)
  2200.         {
  2201.         int bitposx;
  2202.  
  2203.           switch (val)
  2204.           {
  2205.         case 2:
  2206.           val = white;
  2207.           break;
  2208.         case 3:
  2209.           val = black;
  2210.           break;
  2211.           }
  2212.  
  2213.           bitposx = bitpos+(pos>>3);
  2214.           for (j = 0; j < depth; j++)
  2215.           {
  2216.         if (val & (1<<j))
  2217.           *(bitmap.Planes[j]+bitposx) |= 128>>(pos&7);
  2218.           }
  2219.         }
  2220.         pos++;
  2221.       }
  2222.       else
  2223.       {
  2224.       int bitposx;
  2225.  
  2226.         bitposx = bitpos+(pos>>3);
  2227.         for (j = 0; j < depth; j++)
  2228.         {
  2229.           if (black&(1<<j)) *(bitmap.Planes[j]+bitposx) |= ~val;
  2230.           if (white&(1<<j)) *(bitmap.Planes[j]+bitposx) |= val;
  2231.         }
  2232.         pos+=8;
  2233.       }
  2234.  
  2235.     }
  2236.     else
  2237.     {
  2238.       if (val)
  2239.       {
  2240.       int bitposx,xbit = pos*2;
  2241.  
  2242.         if (UsePenTable) val = ZMachinePens[val];
  2243.         bitposx = bitpos+(xbit>>3);
  2244.         for (j = 0; j < depth; j++)
  2245.         {
  2246.           if (val & (1<<j))
  2247.         *(bitmap.Planes[j]+bitposx) |= (128+64)>>(xbit&7);
  2248.         }
  2249.       }
  2250.       pos++;
  2251.     }
  2252.  
  2253.       }
  2254.       while (i >= 0);
  2255.       prev_code = code;
  2256.     }
  2257.     for (i = 0; i < RASSIZE(iwidth,height); i++)
  2258.     {
  2259.       for (j = 0; j < depth; j++) *(mask+i) |= *(bitmap.Planes[j]+i);
  2260.     }
  2261.     BltMaskBitMapRastPort(&bitmap,0,0,RastPort,x,y,iwidth,height,0xE0,mask);
  2262.     if ((Window->Flags & WFLG_BORDERLESS) == 0)
  2263.     {
  2264.       if ((x+iwidth > Window->Width-Window->BorderRight) || (y+height > Window->Height-Window->BorderBottom))
  2265.     RefreshWindowFrame(Window);
  2266.     }
  2267.   }
  2268.  
  2269.   for (i = 0; i < depth; i++)
  2270.   {
  2271.     if (bitmap.Planes[i])
  2272.       FreeRaster(bitmap.Planes[i],iwidth,height);
  2273.   }
  2274.   if (mask) FreeRaster(mask,iwidth,height);
  2275. }
  2276.  
  2277. /*
  2278.  * os_random_seed
  2279.  *
  2280.  * Return an appropriate random seed value in the range from 0 to
  2281.  * 32767, possibly by using the current system time.
  2282.  *
  2283.  */
  2284.  
  2285. int os_random_seed (void)
  2286. {
  2287.   if (user_random_seed == -1) return clock()&32767;
  2288.   return user_random_seed;
  2289. }
  2290.  
  2291. /*
  2292.  * os_restart_game
  2293.  *
  2294.  * This routine allows the interface to interfere with the process of
  2295.  * restarting a game at various stages:
  2296.  *
  2297.  *     RESTART_BEGIN - restart has just begun
  2298.  *     RESTART_WPROP_SET - window properties have been initialised
  2299.  *     RESTART_END - restart is complete
  2300.  *
  2301.  */
  2302.  
  2303. void os_restart_game (int stage)
  2304. {
  2305.   if (stage == RESTART_BEGIN)
  2306.   {
  2307.     USHORT cols[16];
  2308.     int x,y;
  2309.  
  2310.     CheckReset();
  2311.  
  2312.     if (UsingColour && (story_id == BEYOND_ZORK))
  2313.     {
  2314.       if (os_picture_data(1,&x,&y))
  2315.       {
  2316.     CopyMem(CustomColours,cols,16*sizeof(USHORT));
  2317.     os_set_colour(WHITE_COLOUR,BLACK_COLOUR);
  2318.     SafeRectFill(RastPort,
  2319.       Window->BorderLeft,Window->BorderTop,
  2320.       Window->BorderLeft+h_screen_width-1,
  2321.       Window->BorderTop+h_screen_height-1,0);
  2322.     os_draw_picture(1,1,1);
  2323.     os_read_key(0,0);
  2324.     CopyMem(cols,CustomColours,16*sizeof(USHORT));
  2325.     SetZColours();
  2326.       }
  2327.     }
  2328.   }
  2329. }
  2330.  
  2331. void SafeRectFill(struct RastPort *rp,long xMin,long yMin,long xMax,long yMax,unsigned long pen)
  2332. {
  2333. unsigned long saved_pen;
  2334.  
  2335.   saved_pen = rp->FgPen;
  2336.   SetAPen(rp,pen);
  2337.   if (xMax > Window->Width-Window->BorderRight-1) xMax = Window->Width-Window->BorderRight-1;
  2338.   if (yMax > Window->Height-Window->BorderBottom-1) yMax = Window->Height-Window->BorderBottom-1;
  2339.   RectFill(rp,xMin,yMin,xMax,yMax);
  2340.   SetAPen(rp,saved_pen);
  2341. }
  2342.  
  2343. void FlushText(void)
  2344. {
  2345. static int semaphore;
  2346.  
  2347.   if (TextBufferPtr < 1) return;
  2348.   if (semaphore) return;
  2349.   semaphore = 1;
  2350.  
  2351.   Move(RastPort,RastPort->cp_x,RastPort->cp_y+RastPort->TxBaseline);
  2352.  
  2353.   if (justify_pending)
  2354.   {
  2355.   int i,j,len,spaces;
  2356.  
  2357.     for (i = 0, spaces = 0; i < TextBufferPtr; i++)
  2358.       if (*(TextBuffer+i) == ' ') spaces++;
  2359.  
  2360.     len = h_screen_width-option_right_margin-option_left_margin+
  2361.       Window->BorderLeft-RastPort->cp_x-
  2362.       TextLength(RastPort,TextBuffer,TextBufferPtr)+
  2363.       (spaces*TextLength(RastPort," ",1));
  2364.     if (RastPort->AlgoStyle & FSF_BOLD)
  2365.       len -= RastPort->Font->tf_BoldSmear;
  2366.     if (*(TextBuffer+TextBufferPtr-1) == ' ') spaces--;
  2367.  
  2368.     for (i = 0, j = 0; i < TextBufferPtr; i++)
  2369.     {
  2370.       if (*(TextBuffer+i) == ' ')
  2371.       {
  2372.     if (i-j > 0) Text(RastPort,TextBuffer+j,i-j);
  2373.     j = i+1;
  2374.     Move(RastPort,RastPort->cp_x+(len/spaces),RastPort->cp_y);
  2375.     len -= len/spaces;
  2376.     spaces--;
  2377.       }
  2378.     }
  2379.     if (i-j > 0) Text(RastPort,TextBuffer+j,i-j);
  2380.  
  2381.     justify_pending = 0;
  2382.   }
  2383.   else Text(RastPort,TextBuffer,TextBufferPtr);
  2384.  
  2385.   Move(RastPort,RastPort->cp_x,RastPort->cp_y-RastPort->TxBaseline);
  2386.   TextBufferPtr = 0;
  2387.  
  2388.   if ((Window->Flags & WFLG_BORDERLESS) == 0)
  2389.   {
  2390.     if (RastPort->cp_x >= Window->Width-Window->BorderRight)
  2391.       RefreshWindowFrame(Window);
  2392.   }
  2393.  
  2394.   semaphore = 0;
  2395. }
  2396.  
  2397. int GetKey(UWORD *qualifier_addr)
  2398. {
  2399. struct IntuiMessage *imsg;
  2400. ULONG class, port_signals;
  2401. UWORD code, qualifier;
  2402. int i,old_height;
  2403.  
  2404. static unsigned long old_sec = 0,old_mic = 0;
  2405. static unsigned long new_sec = 0,new_mic = 0;
  2406.  
  2407.   FlushText();
  2408.   port_signals = PORTSIG(Window->UserPort)|
  2409.          PORTSIG(TimerMsgPort)|
  2410.          PORTSIG(SoundMsgPort);
  2411.  
  2412.   while(1)
  2413.   {
  2414.     while(imsg = (struct IntuiMessage *)GetMsg(Window->UserPort))
  2415.     {
  2416.       class = imsg->Class;
  2417.       code = imsg->Code;
  2418.       qualifier = imsg->Qualifier;
  2419.       mouse_x = imsg->MouseX-Window->BorderLeft+1;
  2420.       mouse_y = imsg->MouseY-Window->BorderTop+1;
  2421.       new_sec = imsg->Seconds;
  2422.       new_mic = imsg->Micros;
  2423.       if (class == IDCMP_MENUVERIFY) SetColourScheme(0);
  2424.       ReplyMsg((struct Message *)imsg);
  2425.       if (qualifier_addr) *qualifier_addr = qualifier;
  2426.       switch(class)
  2427.       {
  2428.     case IDCMP_RAWKEY:
  2429.       switch (code)
  2430.       {
  2431.         case 0x4C:                    /* Cursor Up */
  2432.           return ZC_ARROW_UP;
  2433.         case 0x4D:                    /* Cursor Down */
  2434.           return ZC_ARROW_DOWN;
  2435.         case 0x4F:                    /* Cursor Left */
  2436.           return ZC_ARROW_LEFT;
  2437.         case 0x4E:                    /* Cursor Right */
  2438.           return ZC_ARROW_RIGHT;
  2439.         case 0x5F:                    /* Help */
  2440.           HelpGuide();
  2441.           break;
  2442.         default:
  2443.           if (code >= 0x50 && code <= 0x59)        /* Function Keys */
  2444.         return code - 0x50 + ZC_FKEY_MIN;
  2445.  
  2446.         static struct InputEvent ie;
  2447.         unsigned char ascii_buffer[1];
  2448.  
  2449.           if (code & IECODE_UP_PREFIX) break;
  2450.           ie.ie_Class = IECLASS_RAWKEY;
  2451.           ie.ie_Prev2DownCode = ie.ie_Prev1DownCode;
  2452.           ie.ie_Prev2DownQual = ie.ie_Prev1DownQual;
  2453.           ie.ie_Prev1DownCode = ie.ie_Code;
  2454.           ie.ie_Prev1DownQual = ie.ie_Qualifier;
  2455.           ie.ie_Code = code;
  2456.           ie.ie_Qualifier = 0;
  2457.           if (MapRawKey(&ie,ascii_buffer,1,0))
  2458.           {
  2459.         switch (*ascii_buffer)
  2460.         {
  2461.           case 'd':
  2462.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_DEBUG;
  2463.             break;
  2464.           case 'h':
  2465.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_HELP;
  2466.             break;
  2467.           case 'n':
  2468.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_RESTART;
  2469.             break;
  2470.           case 'p':
  2471.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_PLAYBACK;
  2472.             break;
  2473.           case 'r':
  2474.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_RECORD;
  2475.             break;
  2476.           case 's':
  2477.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_SEED;
  2478.             break;
  2479.           case 'u':
  2480.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_UNDO;
  2481.             break;
  2482.           case 'x':
  2483.             if (qualifier & QUALIFIER_ALT) return ZC_HKEY_QUIT;
  2484.             break;
  2485.         }
  2486.           }
  2487.  
  2488.           ie.ie_Qualifier = qualifier;
  2489.           if (MapRawKey(&ie,ascii_buffer,1,0))
  2490.           {
  2491.         code = (int)(*ascii_buffer);
  2492.         switch (code)
  2493.         {
  2494.           case 8:
  2495.             return ZC_BACKSPACE;
  2496.           case 9:
  2497.             return 261;
  2498.           case 13:
  2499.             return ZC_RETURN;
  2500.           case 27:
  2501.             return ZC_ESCAPE;
  2502.           case 127:
  2503.             return 260;
  2504.           default:
  2505.             if (qualifier & IEQUALIFIER_NUMERICPAD)
  2506.             {                    /* Numeric Keypad */
  2507.               if (code >= '0' && code <= '9') return code - '0' + ZC_NUMPAD_MIN;
  2508.             }
  2509.             if ((code >= ZC_ASCII_MIN && code <= ZC_ASCII_MAX))
  2510.               return code;
  2511.             if ((code >= ZC_LATIN1_MIN && code <= ZC_LATIN1_MAX))
  2512.               return code;
  2513.         }
  2514.           }
  2515.           break;
  2516.       }
  2517.       break;
  2518.     case IDCMP_MENUPICK:
  2519.       SetColourScheme(1);
  2520.       i = ProcessMenus(code);
  2521.       if (i > 0) return i;
  2522.       break;
  2523.     case IDCMP_MOUSEBUTTONS:
  2524.       if (code == SELECTDOWN)
  2525.       {
  2526.         BOOL double = DoubleClick(old_sec,old_mic,new_sec,new_mic);
  2527.         old_sec = new_sec;
  2528.         old_mic = new_mic;
  2529.         return double ? ZC_DOUBLE_CLICK : ZC_SINGLE_CLICK;
  2530.       }
  2531.       break;
  2532.     case IDCMP_CLOSEWINDOW:
  2533.       Quit(0);
  2534.       break;
  2535.     case IDCMP_CHANGEWINDOW:
  2536.       old_height = h_screen_height;
  2537.       SetScreenDimensions();
  2538.       resize_screen();
  2539.       InputMax2 = MIN(InputMax1,Window->Width-Window->BorderRight);
  2540.  
  2541.       if (PreviousRows > h_screen_rows)
  2542.       {
  2543.         SafeRectFill(RastPort,
  2544.           Window->BorderLeft,
  2545.           Window->BorderTop+(h_screen_rows*TextHeight),
  2546.           Window->Width-Window->BorderRight-1,
  2547.           Window->Height-Window->BorderBottom-1,BackColour);
  2548.  
  2549.         if (RastPort->cp_y+TextHeight > Window->Height-Window->BorderBottom)
  2550.         {
  2551.           Move(RastPort,RastPort->cp_x,Window->BorderTop+((h_screen_rows-1)*TextHeight));
  2552.           SafeRectFill(RastPort,
  2553.         Window->BorderLeft,
  2554.         RastPort->cp_y,
  2555.         Window->Width-Window->BorderRight-1,
  2556.         RastPort->cp_y+TextHeight-1,BackColour);
  2557.           PreviousRows = h_screen_rows;
  2558.           return 264;                /* Window Sizing */
  2559.         }
  2560.       }
  2561.       PreviousRows = h_screen_rows;
  2562.       break;
  2563.       }
  2564.     }
  2565.     if (GetMsg(TimerMsgPort))
  2566.     {
  2567.       TimerActive = 0;
  2568.       return ZC_TIME_OUT;
  2569.     }
  2570.     if (GetMsg(SoundMsgPort))
  2571.     {
  2572.       if (GetMsg(SoundMsgPort)) end_of_sound();
  2573.       SamplePlaying = 0;
  2574.     }
  2575.     ModifyIDCMP(Window,Window->IDCMPFlags | IDCMP_MENUVERIFY);
  2576.     Wait(port_signals);
  2577.     ModifyIDCMP(Window,Window->IDCMPFlags & ~IDCMP_MENUVERIFY);
  2578.   }
  2579. }
  2580.  
  2581. void DrawCursor(int under)
  2582. {
  2583. int size;
  2584. BYTE saved_draw_mode;
  2585.  
  2586.   FlushText();
  2587.   if (cursor_state == 0) return;
  2588.   size = (under == 0) ? RastPort->TxWidth : CharLength(under);
  2589.  
  2590.   saved_draw_mode = RastPort->DrawMode;
  2591.   SetDrMd(RastPort,COMPLEMENT);
  2592.   if (UsingColour == 3) SetWrMsk(RastPort,0x01);
  2593.  
  2594.   SafeRectFill(RastPort,
  2595.     RastPort->cp_x,
  2596.     RastPort->cp_y,
  2597.     RastPort->cp_x+size-1,
  2598.     RastPort->cp_y+TextHeight-1,0);
  2599.  
  2600.   SetDrMd(RastPort,saved_draw_mode);
  2601.   if (UsingColour == 3) SetWrMsk(RastPort,0xFF);
  2602. }
  2603.  
  2604. void ShowAbout(void)
  2605. {
  2606. char *title, *after_title;
  2607. char *authors, *before_authors, *after_authors;
  2608. char *level;
  2609.  
  2610.   title = GetGameTitle(current_game);
  2611.   authors = GetGameAuthors(current_game);
  2612.   level = GetGameLevel(current_game);
  2613.  
  2614.   after_title = (strcmp(title,"") == 0) ? "" : "\n";
  2615.   if (strcmp(authors,"") == 0)
  2616.   {
  2617.     before_authors = "";
  2618.     after_authors = (strcmp(title,"") == 0) ? "" : "\n";
  2619.   }
  2620.   else
  2621.   {
  2622.     before_authors = "Written by ";
  2623.     after_authors = (strcmp(level,"") == 0) ? "\n\n" : "\n";
  2624.   }
  2625.  
  2626.   Requester(Window,
  2627.     "%s%s%s%s%s%s"
  2628.     "Frotz 2.32 Standard 1.0 Infocom Interpreter\n"
  2629.     "Copyright 1995-97 by Stefan Jokisch\n\n"
  2630.     "Amiga Release 10\n"
  2631.     "Amiga Version by David Kinder",
  2632.     "Continue",
  2633.     title,after_title,before_authors,authors,after_authors,level);
  2634. }
  2635.  
  2636. int CharLength(int c)
  2637. {
  2638. unsigned char buffer;
  2639.  
  2640.   if (c < 0) c += 256;
  2641.   buffer = (unsigned char)c;
  2642.   return TextLength(RastPort,&buffer,1);
  2643. }
  2644.  
  2645. void MoveTextRow(int offset,int max)
  2646. {
  2647. int xSource,xDest;
  2648.  
  2649.   xSource = RastPort->cp_x;
  2650.   xDest = RastPort->cp_x+offset;
  2651.   ClipBlit(RastPort,
  2652.     xSource,
  2653.     RastPort->cp_y,
  2654.     RastPort,
  2655.     xDest,
  2656.     RastPort->cp_y,
  2657.     max-MAX(xSource,xDest),
  2658.     TextHeight,0xC0);
  2659. }
  2660.  
  2661. void CursorLeftEnd(unsigned char *buffer,int *pos)
  2662. {
  2663.   while (*pos > 0)
  2664.   {
  2665.     (*pos)--;
  2666.     Move(RastPort,RastPort->cp_x-CharLength(*(buffer+*pos)),RastPort->cp_y);
  2667.   }
  2668. }
  2669.  
  2670. void CursorRightEnd(unsigned char *buffer,int *pos)
  2671. {
  2672.   while (*pos < strlen(buffer))
  2673.   {
  2674.     Move(RastPort,RastPort->cp_x+CharLength(*(buffer+*pos)),RastPort->cp_y);
  2675.     (*pos)++;
  2676.   }
  2677. }
  2678.  
  2679. int FitTextLine(unsigned char *pointer,int new)
  2680. {
  2681. int a,b;
  2682.  
  2683.   a = TextLength(RastPort,pointer,strlen(pointer))+CharLength(new)+
  2684.     RastPort->cp_x+RastPort->TxWidth;
  2685.   b = Window->BorderLeft+h_screen_width-
  2686.     option_right_margin-option_left_margin;
  2687.   return (a > b) ? 0 : 1;
  2688. }
  2689.  
  2690. void Quit(int code)
  2691. {
  2692.   last_text_out = 0;
  2693.   os_reset_screen();
  2694.   exit(code);
  2695. }
  2696.  
  2697. void StartTimer(int timeout)
  2698. {
  2699.   if ((TimerActive == 0) && (timeout > 0))
  2700.   {
  2701.     TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
  2702.     TimerRequest->tr_node.io_Message.mn_ReplyPort = TimerMsgPort;
  2703.     TimerRequest->tr_time.tv_secs = timeout/10;
  2704.     TimerRequest->tr_time.tv_micro = (timeout-(TimerRequest->tr_time.tv_secs*10))*100000;
  2705.     SendIO((struct IORequest *)TimerRequest);
  2706.     TimerActive = 1;
  2707.   }
  2708. }
  2709.  
  2710. void StopTimer(void)
  2711. {
  2712.   if (TimerActive != 0)
  2713.   {
  2714.     if (GetMsg(TimerMsgPort) == 0)
  2715.     {
  2716.       AbortIO((struct IORequest *)TimerRequest);
  2717.       WaitIO((struct IORequest *)TimerRequest);
  2718.     }
  2719.     TimerActive = 0;
  2720.   }
  2721. }
  2722.  
  2723. void StoreInHistory(unsigned char *line)
  2724. {
  2725. int i;
  2726.  
  2727.   if ((*line != 0) && (SafeCmp(*(History+HISTORY_LINES-1),line) != 0))
  2728.   {
  2729.     if (*History) FreeVec(*History);
  2730.     for (i = 0; i < HISTORY_LINES-1; i++) *(History+i) = *(History+i+1);
  2731.     if (*(History+HISTORY_LINES-1) = AllocVec(strlen(line)+1,MEMF_CLEAR))
  2732.       strcpy(*(History+HISTORY_LINES-1),line);
  2733.   }
  2734.   HistoryPosition = HISTORY_LINES;
  2735. }
  2736.  
  2737. int SafeCmp(const char *a,const char *b)
  2738. {
  2739.   if ((a == 0) || (b == 0)) return 1;
  2740.   return strcmp(a,b);
  2741. }
  2742.  
  2743. void PutIntoBuffer(unsigned char *buffer,unsigned char *new,int *pos,int max_size)
  2744. {
  2745.   if (new == 0) return;
  2746.  
  2747.   DrawCursor(*(buffer+*pos));
  2748.  
  2749. int saved_x_position;
  2750. int saved_colour;
  2751. int i;
  2752.  
  2753.   CursorLeftEnd(buffer,pos);
  2754.   saved_colour = RastPort->FgPen;
  2755.   saved_x_position = RastPort->cp_x;
  2756.   SetAPen(RastPort,RastPort->BgPen);
  2757.   for (i = 0; i < strlen(buffer); i++) os_display_char(*(buffer+i));
  2758.   FlushText();
  2759.   SetAPen(RastPort,saved_colour);
  2760.   Move(RastPort,saved_x_position,RastPort->cp_y);
  2761.  
  2762.   *buffer = 0;
  2763.  
  2764.   while(1)
  2765.   {
  2766.     if ((FitTextLine(buffer,*(new+*pos)) == 0) || (*(new+*pos) == 0) || (*pos == max_size))
  2767.     {
  2768.       for (i = 0; i < strlen(buffer); i++) os_display_char(*(buffer+i));
  2769.       FlushText();
  2770.       DrawCursor(*(buffer+*pos));
  2771.       return;
  2772.     }
  2773.     else
  2774.     {
  2775.       *(buffer+*pos) = *(new+*pos);
  2776.       (*pos)++;
  2777.       *(buffer+*pos) = 0;
  2778.     }
  2779.   }
  2780. }
  2781.  
  2782. void RedrawLine(unsigned char *buffer,int *pos,int max_size)
  2783. {
  2784. char *current_buffer;
  2785.  
  2786.   DrawCursor(*(buffer+*pos));
  2787.   if ((current_buffer = AllocVec(max_size,MEMF_CLEAR)) == 0) return;
  2788.   strcpy(current_buffer,buffer);
  2789.   PutIntoBuffer(buffer,current_buffer,pos,max_size);
  2790.   FreeVec(current_buffer);
  2791. }
  2792.  
  2793. int ProcessMenus(UWORD menu_number)
  2794. {
  2795. struct MenuItem *menu_item;
  2796.  
  2797.   while (menu_number != MENUNULL)
  2798.   {
  2799.     switch (MENUNUM(menu_number))
  2800.     {
  2801.       case 0:
  2802.     switch (ITEMNUM(menu_number))
  2803.     {
  2804.       case 0:
  2805.         if (OpenPreferences()) return ZC_HKEY_RESTART;
  2806.         break;
  2807.       case 1:
  2808.         HelpGuide();
  2809.         break;
  2810.       case 2:
  2811.         ShowAbout();
  2812.         break;
  2813.       case 4:
  2814.         Quit(0);
  2815.         break;
  2816.     }
  2817.     break;
  2818.       case 1:
  2819.     if (ITEMNUM(menu_number) == 11)
  2820.     {
  2821.       if (h_version == V3)
  2822.       {
  2823.         if (ItemAddress(Menus,menu_number)->Flags & CHECKED)
  2824.         {
  2825.           h_config |= CONFIG_TANDY;
  2826.           SET_BYTE(H_CONFIG,h_config)
  2827.           user_tandy_bit = 1;
  2828.         }
  2829.         else
  2830.         {
  2831.           h_config &= ~CONFIG_TANDY;
  2832.           SET_BYTE(H_CONFIG,h_config)
  2833.           user_tandy_bit = -1;
  2834.         }
  2835.       }
  2836.     }
  2837.     else return (menu_number+2000);
  2838.     break;
  2839.       case 2:
  2840.     return (menu_number+2000);
  2841.     break;
  2842.     }
  2843.     menu_item = ItemAddress(Menus,menu_number);
  2844.     menu_number = menu_item->NextSelect;
  2845.   }
  2846.   return 0;
  2847. }
  2848.  
  2849. int Terminate(unsigned char *buffer,int pos,int c,int pen)
  2850. {
  2851.   DrawCursor(*(buffer+pos));
  2852.   CursorRightEnd(buffer,&pos);
  2853.   SetAPen(RastPort,pen);
  2854.   if (c == ZC_RETURN) StoreInHistory(buffer);
  2855.   last_text_out = 0;
  2856.   return c;
  2857. }
  2858.  
  2859. void HelpGuide(void)
  2860. {
  2861. struct NewAmigaGuide frotz_guide =
  2862.   { 0,"Frotz.guide",0,0,0,0,0,0,0,0,0,0,0 };
  2863.  
  2864.   frotz_guide.nag_Screen = Window->WScreen;
  2865.   if (AmigaGuideBase == 0)
  2866.     AmigaGuideBase = OpenLibrary("amigaguide.library",34);
  2867.   if (AmigaGuideBase != 0)
  2868.   {
  2869.     SetColourScheme(0);
  2870.     CloseAmigaGuide(OpenAmigaGuide(&frotz_guide,TAG_DONE));
  2871.     SetColourScheme(1);
  2872.   }
  2873. }
  2874.  
  2875. int InitializeSound(void)
  2876. {
  2877.   SetupSoundDirectory();
  2878.  
  2879.   if ((SoundRequest = (struct IOAudio *)
  2880.     CreateIORequest(SoundMsgPort,sizeof(struct IOAudio))) == 0) return 0;
  2881.   if ((SoundLeftRequest = (struct IOAudio *)
  2882.     CreateIORequest(SoundMsgPort,sizeof(struct IOAudio))) == 0) return 0;
  2883.   if ((SoundRightRequest = (struct IOAudio *)
  2884.     CreateIORequest(SoundMsgPort,sizeof(struct IOAudio))) == 0) return 0;
  2885.  
  2886. static unsigned char allocation_map[] = { 3,5,10,12 };
  2887.  
  2888.   SoundRequest->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
  2889.   SoundRequest->ioa_Request.io_Command = ADCMD_ALLOCATE;
  2890.   SoundRequest->ioa_Request.io_Flags = ADIOF_NOWAIT;
  2891.   SoundRequest->ioa_Data = allocation_map;
  2892.   SoundRequest->ioa_Length = sizeof(allocation_map);
  2893.  
  2894.   if ((SoundOpenCode =
  2895.     OpenDevice("audio.device",0,(struct IORequest *)SoundRequest,0)) != 0) return 0;
  2896.  
  2897. unsigned long channels;
  2898.  
  2899.   channels = (unsigned long)SoundRequest->ioa_Request.io_Unit;
  2900.   CopyMem(SoundRequest,SoundLeftRequest,sizeof(struct IOAudio));
  2901.   SoundLeftRequest->ioa_Request.io_Unit = (void *)(channels & 9);
  2902.   CopyMem(SoundRequest,SoundRightRequest,sizeof(struct IOAudio));
  2903.   SoundRightRequest->ioa_Request.io_Unit = (void *)(channels & 6);
  2904.  
  2905.   return 1;
  2906. }
  2907.  
  2908. void ResetSound(void)
  2909. {
  2910.   os_finish_with_sample();
  2911.   if (SoundOpenCode == 0) CloseDevice((struct IORequest *)SoundRequest);
  2912.   if (SoundRequest) DeleteIORequest(SoundRequest);
  2913.   if (SoundLeftRequest) DeleteIORequest(SoundLeftRequest);
  2914.   if (SoundRightRequest) DeleteIORequest(SoundRightRequest);
  2915. }
  2916.  
  2917. void SetupSoundDirectory(void)
  2918. {
  2919. char base_dir[MAX_FILE_NAME+1];
  2920. BPTR lock;
  2921.  
  2922.   if (lock = Lock(story_name,ACCESS_READ))
  2923.   {
  2924.     NameFromLock(lock,base_dir,MAX_FILE_NAME);
  2925.     UnLock(lock);
  2926.   }
  2927.   else strcpy(base_dir,story_name);
  2928.   *FilePart(base_dir) = 0;
  2929.  
  2930.   switch (current_game)
  2931.   {
  2932.     case 14:                /* The Lurking Horror */
  2933.       strcpy(SoundDirectory,base_dir);
  2934.       AddPart(SoundDirectory,"LurkingHorrorSound",MAX_FILE_NAME);
  2935.       if (lock = Lock(SoundDirectory,ACCESS_READ))
  2936.       {
  2937.     UnLock(lock);
  2938.     return;
  2939.       }
  2940.       break;
  2941.     case 20:                /* Sherlock */
  2942.       strcpy(SoundDirectory,base_dir);
  2943.       AddPart(SoundDirectory,"SherlockSound",MAX_FILE_NAME);
  2944.       if (lock = Lock(SoundDirectory,ACCESS_READ))
  2945.       {
  2946.     UnLock(lock);
  2947.     return;
  2948.       }
  2949.       break;
  2950.   }
  2951.   strcpy(SoundDirectory,base_dir);
  2952.   AddPart(SoundDirectory,"Sound",MAX_FILE_NAME);
  2953. }
  2954.  
  2955. BPTR LockSoundData(int number)
  2956. {
  2957. BPTR sound_name_file;
  2958. BPTR sound_mac_file;
  2959. BPTR lock;
  2960. char sound_name[MAX_FILE_NAME+1];
  2961. char sound_data[MAX_FILE_NAME+1];
  2962. char new_sound_name[MAX_FILE_NAME+1];
  2963. char *new_sound_ptr;
  2964. struct MacintoshMid mac_mid_data;
  2965.  
  2966.   SampleUnsigned = 0;
  2967.   sprintf(sound_name,"%s/s%d.nam",SoundDirectory,number);
  2968.   sprintf(sound_data,"%s/s%d.dat",SoundDirectory,number);
  2969.  
  2970.   if (sound_name_file = Open(sound_name,MODE_OLDFILE))
  2971.   {
  2972.     Seek(sound_name_file,2,OFFSET_BEGINNING);
  2973.     new_sound_ptr = new_sound_name;
  2974.     do
  2975.     {
  2976.       *new_sound_ptr = FGetC(sound_name_file);
  2977.     }
  2978.     while (*new_sound_ptr++ != 0);
  2979.     sprintf(sound_data,"%s/%s",SoundDirectory,new_sound_name);
  2980.     Close(sound_name_file);
  2981.   }
  2982.   if ((lock = Lock(sound_data,ACCESS_READ)) != 0) return lock;
  2983.  
  2984.   sprintf(sound_data,"%s/s%d",SoundDirectory,number);
  2985.   if ((lock = Lock(sound_data,ACCESS_READ)) != 0)
  2986.   {
  2987.     SampleUnsigned = 1;
  2988.     return lock;
  2989.   }
  2990.  
  2991.   sprintf(sound_data,"%s/m%d",SoundDirectory,number);
  2992.   if ((sound_mac_file = Open(sound_data,MODE_OLDFILE)) != 0)
  2993.   {
  2994.     SampleUnsigned = 1;
  2995.     Read(sound_mac_file,&mac_mid_data,sizeof(struct MacintoshMid));
  2996.     Close(sound_mac_file);
  2997.     sprintf(sound_data,"%s/%s",SoundDirectory,mac_mid_data.SoundFileName);
  2998.     return Lock(sound_data,ACCESS_READ);
  2999.   }
  3000.  
  3001.   switch (current_game)
  3002.   {
  3003.     case 14:                /* The Lurking Horror */
  3004.       sprintf(sound_data,"%s/lurkin%.2d.snd",SoundDirectory,number);
  3005.       break;
  3006.     case 20:                /* Sherlock */
  3007.       sprintf(sound_data,"%s/sherlo%.2d.snd",SoundDirectory,number);
  3008.       break;
  3009.     default:
  3010.       return 0;
  3011.       break;
  3012.   }
  3013.   if ((lock = Lock(sound_data,ACCESS_READ)) != 0)
  3014.   {
  3015.     SampleUnsigned = 1;
  3016.     return lock;
  3017.   }
  3018.  
  3019.   return 0;
  3020. }
  3021.  
  3022. void WaitForMsg(struct MsgPort *port)
  3023. {
  3024.   WaitPort(port);
  3025.   GetMsg(port);
  3026. }
  3027.  
  3028. void BusyPointer(struct Window *window,int busy)
  3029. {
  3030.   if ((IntuitionBase->lib_Version >= 39) && (window))
  3031.     SetWindowPointer(window,WA_BusyPointer,busy,TAG_DONE);
  3032. }
  3033.  
  3034. LONG Requester(struct Window *window,UBYTE *text,UBYTE *gadgets,...)
  3035. {
  3036. va_list arguments;
  3037. LONG return_value;
  3038. static struct EasyStruct requester =
  3039.   { sizeof(struct EasyStruct),0,"Frotz",0,0 };
  3040.  
  3041.   requester.es_TextFormat = text;
  3042.   requester.es_GadgetFormat = gadgets;
  3043.   va_start(arguments,gadgets);
  3044.   SetColourScheme(0);
  3045.   BusyPointer(window,1);
  3046.   return_value = EasyRequestArgs(window,&requester,0,arguments);
  3047.   BusyPointer(window,0);
  3048.   SetColourScheme(1);
  3049.   va_end(arguments);
  3050.   return return_value;
  3051. }
  3052.  
  3053. void CloseDisplay(void)
  3054. {
  3055. int i;
  3056.  
  3057.   FlushText();
  3058.   last_text_out = 0;
  3059.  
  3060.   if (h_version == V3)
  3061.   {
  3062.     if (h_flags & OLD_SOUND_FLAG) ResetSound();
  3063.   }
  3064.   if (h_version >= V4)
  3065.   {
  3066.     if (h_flags & SOUND_FLAG) ResetSound();
  3067.   }
  3068.  
  3069.   for (i = 0; i < HISTORY_LINES; i++)
  3070.   {
  3071.     if (*(History+i)) FreeVec(*(History+i));
  3072.     *(History+i) = 0;
  3073.   }
  3074.  
  3075.   StopTimer();
  3076.   if (TimerOpenCode == 0) CloseDevice((struct IORequest *)TimerRequest);
  3077.   if (TimerRequest) DeleteIORequest(TimerRequest);
  3078.   if (TimerMsgPort) DeleteMsgPort(TimerMsgPort);
  3079.   if (SoundMsgPort) DeleteMsgPort(SoundMsgPort);
  3080.  
  3081.   if (GfxMemory) FreeVec(GfxMemory);
  3082.  
  3083.   CloseBGUI(2);
  3084.   if (SaveIcon) FreeDiskObject(SaveIcon);
  3085.   if (ScreenFont) CloseFont(ScreenFont);
  3086.   if (OpenedTextFont) CloseFont(OpenedTextFont);
  3087.   if (OpenedFixedFont) CloseFont(OpenedFixedFont);
  3088.   if (Menus) FreeMenus(Menus);
  3089.   if (Visual) FreeVisualInfo(Visual);
  3090.   if (ThisProcess) ThisProcess->pr_WindowPtr = OldWindowPtr;
  3091.   if (Window) CloseWindow(Window);
  3092.   if (Screen) CloseScreen(Screen);
  3093.   FreePenTable();
  3094.   if (DefaultPubScreen) UnlockPubScreen(0,DefaultPubScreen);
  3095.   if (FileRequester) FreeAslRequest(FileRequester);
  3096.   if (AmigaGuideBase) CloseLibrary(AmigaGuideBase);
  3097.   if (KeymapBase) CloseLibrary(KeymapBase);
  3098.  
  3099.   TimerRequest = 0;
  3100.   TimerMsgPort = 0;
  3101.  
  3102.   SoundOpenCode = -1;
  3103.   SoundRequest = 0;
  3104.   SoundLeftRequest = 0;
  3105.   SoundRightRequest = 0;
  3106.   SoundMsgPort = 0;
  3107.  
  3108.   GfxMemory = 0;
  3109.  
  3110.   SaveIcon = 0;
  3111.   OpenedTextFont = 0;
  3112.   OpenedFixedFont = 0;
  3113.   Menus = 0;
  3114.   Visual = 0;
  3115.   ThisProcess = 0;
  3116.   Window = 0;
  3117.   Screen = 0;
  3118.   DefaultPubScreen = 0;
  3119.   FileRequester = 0;
  3120.   AmigaGuideBase = 0;
  3121.   KeymapBase = 0;
  3122. }
  3123.  
  3124. void GetScreenRatio(struct Screen *screen)
  3125. {
  3126. struct TagItem vti[] =
  3127.   { VTAG_VIEWPORTEXTRA_GET,0,
  3128.     VTAG_END_CM,0 };
  3129. struct ViewPortExtra *vpe;
  3130.  
  3131.   ScaleX = 1000;
  3132.   ScaleY = 1000;
  3133.   ScreenWidth = screen->Width;
  3134.   ScreenHeight = screen->Height;
  3135.   if (screen->ViewPort.ColorMap)
  3136.   {
  3137.     if (VideoControl(screen->ViewPort.ColorMap,vti) == 0)
  3138.     {
  3139.       vpe = (struct ViewPortExtra *)vti[0].ti_Data;
  3140.       ScreenWidth = vpe->DisplayClip.MaxX - vpe->DisplayClip.MinX + 1;
  3141.       ScreenHeight = vpe->DisplayClip.MaxY - vpe->DisplayClip.MinY + 1;
  3142.       ScaleX = MAX((ScreenWidth*1000)/640,1000);
  3143.       ScaleY = MAX((ScreenHeight*1000)/256,1000);
  3144.     }
  3145.   }
  3146. }
  3147.  
  3148. void SetScreenDimensions(void)
  3149. {
  3150.   h_screen_width = Window->Width-Window->BorderLeft-Window->BorderRight;
  3151.   h_screen_height = Window->Height-Window->BorderTop-Window->BorderBottom;
  3152.   h_font_width = TextWidth;
  3153.   h_font_height = TextHeight;
  3154.   h_screen_cols = h_screen_width/h_font_width;
  3155.   h_screen_rows = h_screen_height/h_font_height;
  3156. }
  3157.  
  3158. void SetColourScheme(int custom)
  3159. {
  3160. static USHORT previous;
  3161.  
  3162.   if ((UsingColour > 1) && (Screen))
  3163.     LoadRGB4(&Screen->ViewPort,custom ? CustomColours : SystemColours,16);
  3164. }
  3165.  
  3166. void Justifiable(void)
  3167. {
  3168.   if (h_version == V6) return;
  3169.   if ((MoreFrotzPrefs.Flags & PREFS_JUSTIFICATION) == 0) return;
  3170.   if ((TextFont->tf_Flags & FPF_PROPORTIONAL) == 0) return;
  3171.   if (cwin != 0) return;
  3172.   justify_pending = 1;
  3173. }
  3174.  
  3175. void LimitWindow(int limit,int x)
  3176. {
  3177.   if (limit)
  3178.   {
  3179.     WindowLimits(Window,
  3180.       RastPort->cp_x+RastPort->TxWidth+Window->BorderRight+x,
  3181.       Window->BorderTop+Window->BorderBottom+(TextHeight*3),
  3182.       ~0,~0);
  3183.   }
  3184.   else
  3185.   {
  3186.     WindowLimits(Window,
  3187.       Window->Width,Window->Height,
  3188.       Window->Width,Window->Height);
  3189.   }
  3190. }
  3191.  
  3192. void GetCursorPos(int *row, int *col)
  3193. {
  3194.   *row = RastPort->cp_y-Window->BorderTop+1;
  3195.   *col = RastPort->cp_x-Window->BorderLeft+1;
  3196. }
  3197.  
  3198. int SafeTryOpen(char *path,char *ext,BPTR *handle)
  3199. {
  3200. char *file,*extpos;
  3201.  
  3202.   if (*handle != 0) return 0;
  3203.  
  3204.   file = FilePart(path);
  3205.   if ((extpos = strrchr(file,'.')) == 0) extpos = file+strlen(file);
  3206.   strcpy(extpos,ext);
  3207.  
  3208.   *handle = Open(path,MODE_OLDFILE);
  3209.   return *handle;
  3210. }
  3211.  
  3212. void LoadGraphicsFile(void)
  3213. {
  3214. char gfx_path[MAX_FILE_NAME+1];
  3215. char *file_part;
  3216. BPTR fh = 0;
  3217. struct FileInfoBlock *fib;
  3218.  
  3219.   strcpy(gfx_path,story_name);
  3220.   if (SafeTryOpen(gfx_path,".mg1",&fh)) GfxType = GFX_IBM_MCGA;
  3221.   if (SafeTryOpen(gfx_path,".cg1",&fh)) GfxType = GFX_IBM_CGA;
  3222.   if (SafeTryOpen(gfx_path,".gfx",&fh)) GfxType = GFX_AMIGA;
  3223.   if (file_part = FilePart(gfx_path))
  3224.   {
  3225.     *file_part = '\0';
  3226.     strcat(gfx_path,"Pic");
  3227.     if (SafeTryOpen(gfx_path,".data",&fh)) GfxType = GFX_AMIGA;
  3228.   }
  3229.   if (fh == 0) return;
  3230.  
  3231.   if (fib = AllocDosObjectTags(DOS_FIB,TAG_DONE))
  3232.   {
  3233.     ExamineFH(fh,fib);
  3234.     if (GfxMemory = AllocVec(fib->fib_Size,0))
  3235.     {
  3236.       Read(fh,GfxMemory,fib->fib_Size);
  3237.       GfxHeader = (struct GraphicsHeader *)GfxMemory;
  3238.     }
  3239.     FreeDosObject(DOS_FIB,fib);
  3240.   }
  3241.   Close(fh);
  3242. }
  3243.  
  3244. int ByteSwap(unsigned short n)
  3245. {
  3246.   if (GfxType != GFX_AMIGA) return ((n>>8)|((n&255)<<8));
  3247.   return n;
  3248. }
  3249.  
  3250. char *FindPicture(int pic)
  3251. {
  3252. char *info;
  3253. int i;
  3254.  
  3255.   info = GfxMemory+sizeof(struct GraphicsHeader);
  3256.   for (i = 0; i < ByteSwap(GfxHeader->Images); i++)
  3257.   {
  3258.     if (pic == ByteSwap(*(short *)(info+PIC_NUMBER))) return info;
  3259.     info += GfxHeader->InfoSize;
  3260.   }
  3261.   return 0;
  3262. }
  3263.  
  3264. ULONG GetColour32(ULONG col)
  3265. {
  3266.   col |= (col<<4);
  3267.   col |= (col<<8);
  3268.   col |= (col<<16);
  3269.   col |= (col<<32);
  3270.   return col;
  3271. }
  3272.  
  3273. void FreePenTable(void)
  3274. {
  3275.   if (DefaultPubScreen && UsePenTable)
  3276.   {
  3277.     if (IntuitionBase->lib_Version >= 39)
  3278.     {
  3279.     int i;
  3280.  
  3281.       for (i = 0; i < 16; i++)
  3282.       {
  3283.     ReleasePen(DefaultPubScreen->ViewPort.ColorMap,ZMachinePens[i]);
  3284.     ZMachinePens[i] = -1;
  3285.       }
  3286.     }
  3287.   }
  3288.   UsePenTable = 0;
  3289. }
  3290.  
  3291. struct TextFont *OpenCorrectFont(struct TextAttr *textAttr)
  3292. {
  3293. struct TextAttr topaz8 = {"topaz.font",8,FS_NORMAL,0};
  3294.  
  3295.   if (h_version == V6 && MoreFrotzPrefs.V6Style == V6_640200)
  3296.     return OpenFont(&topaz8);
  3297.   return OpenDiskFont(textAttr);
  3298. }
  3299.  
  3300. int SizeGadgetHeight(struct Screen *screen)
  3301. {
  3302. struct DrawInfo *dri;
  3303. struct Image *size;
  3304. int height = 0;
  3305.  
  3306.   if (dri = GetScreenDrawInfo(screen))
  3307.   {
  3308.     if (size = NewObject(NULL,SYSICLASS,
  3309.       SYSIA_DrawInfo,dri,SYSIA_Which,SIZEIMAGE,TAG_DONE))
  3310.     {
  3311.       height = size->Height;
  3312.       DisposeObject(size);
  3313.     }
  3314.     FreeScreenDrawInfo(screen,dri);
  3315.   }
  3316.   return height;
  3317. }
  3318.  
  3319. void SetZColours(void)
  3320. {
  3321.   if ((Screen == NULL) && UsingColour)
  3322.   {
  3323.     int i;
  3324.  
  3325.     for (i = 0; i < 8; i++)
  3326.     {
  3327.       SetRGB4(&(Window->WScreen->ViewPort),ZMachinePens[i],
  3328.     (ZColours[i]&0x0F00)>>8,
  3329.     (ZColours[i]&0x00F0)>>4,
  3330.     (ZColours[i]&0x000F));
  3331.     }
  3332.   }
  3333. }
  3334.